From 1cad49bcd9ea70b3e02ce150e409177eab8851dd Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 7 Mar 2023 20:46:00 +0000 Subject: [PATCH 001/217] 8303433: Bump update version for OpenJDK: jdk-17.0.8 Reviewed-by: rrich --- .jcheck/conf | 2 +- make/conf/version-numbers.conf | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.jcheck/conf b/.jcheck/conf index 495417d1972..b8301502d72 100644 --- a/.jcheck/conf +++ b/.jcheck/conf @@ -1,7 +1,7 @@ [general] project=jdk-updates jbs=JDK -version=17.0.7 +version=17.0.8 [checks] error=author,committer,reviewers,merge,issues,executable,symlink,message,hg-tag,whitespace,problemlists diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf index 2b871e10237..6e53ab7dc50 100644 --- a/make/conf/version-numbers.conf +++ b/make/conf/version-numbers.conf @@ -28,12 +28,12 @@ DEFAULT_VERSION_FEATURE=17 DEFAULT_VERSION_INTERIM=0 -DEFAULT_VERSION_UPDATE=7 +DEFAULT_VERSION_UPDATE=8 DEFAULT_VERSION_PATCH=0 DEFAULT_VERSION_EXTRA1=0 DEFAULT_VERSION_EXTRA2=0 DEFAULT_VERSION_EXTRA3=0 -DEFAULT_VERSION_DATE=2023-04-18 +DEFAULT_VERSION_DATE=2023-07-18 DEFAULT_VERSION_CLASSFILE_MAJOR=61 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`" DEFAULT_VERSION_CLASSFILE_MINOR=0 DEFAULT_VERSION_DOCS_API_SINCE=11 From 1ad9e6843ab54dbd16631474969986c1de87dd9b Mon Sep 17 00:00:00 2001 From: Vladimir Kempik Date: Mon, 13 Mar 2023 07:23:30 +0000 Subject: [PATCH 002/217] 8292407: Improve Weak CAS VarHandle/Unsafe tests resilience under spurious failures Backport-of: 6e6202c14d0f6dd26369f21883ff317057aa469f --- ...dkInternalMiscUnsafeAccessTestBoolean.java | 23 +++++++- .../JdkInternalMiscUnsafeAccessTestByte.java | 23 +++++++- .../JdkInternalMiscUnsafeAccessTestChar.java | 23 +++++++- ...JdkInternalMiscUnsafeAccessTestDouble.java | 23 +++++++- .../JdkInternalMiscUnsafeAccessTestFloat.java | 23 +++++++- .../JdkInternalMiscUnsafeAccessTestInt.java | 23 +++++++- .../JdkInternalMiscUnsafeAccessTestLong.java | 23 +++++++- ...JdkInternalMiscUnsafeAccessTestObject.java | 23 +++++++- .../JdkInternalMiscUnsafeAccessTestShort.java | 23 +++++++- .../SunMiscUnsafeAccessTestBoolean.java | 19 ++++++- .../unsafe/SunMiscUnsafeAccessTestByte.java | 19 ++++++- .../unsafe/SunMiscUnsafeAccessTestChar.java | 19 ++++++- .../unsafe/SunMiscUnsafeAccessTestDouble.java | 19 ++++++- .../unsafe/SunMiscUnsafeAccessTestFloat.java | 19 ++++++- .../unsafe/SunMiscUnsafeAccessTestInt.java | 19 ++++++- .../unsafe/SunMiscUnsafeAccessTestLong.java | 19 ++++++- .../unsafe/SunMiscUnsafeAccessTestObject.java | 19 ++++++- .../unsafe/SunMiscUnsafeAccessTestShort.java | 19 ++++++- .../unsafe/X-UnsafeAccessTest.java.template | 23 +++++++- .../invoke/VarHandles/VarHandleBaseTest.java | 21 +++++++- .../VarHandleTestAccessBoolean.java | 12 +++++ .../VarHandles/VarHandleTestAccessByte.java | 12 +++++ .../VarHandles/VarHandleTestAccessChar.java | 12 +++++ .../VarHandles/VarHandleTestAccessDouble.java | 12 +++++ .../VarHandles/VarHandleTestAccessFloat.java | 12 +++++ .../VarHandles/VarHandleTestAccessInt.java | 12 +++++ .../VarHandles/VarHandleTestAccessLong.java | 12 +++++ .../VarHandles/VarHandleTestAccessShort.java | 12 +++++ .../VarHandles/VarHandleTestAccessString.java | 12 +++++ .../VarHandleTestByteArrayAsDouble.java | 8 +++ .../VarHandleTestByteArrayAsFloat.java | 8 +++ .../VarHandleTestByteArrayAsInt.java | 8 +++ .../VarHandleTestByteArrayAsLong.java | 8 +++ ...arHandleTestMethodHandleAccessBoolean.java | 52 ++++++++++++++----- .../VarHandleTestMethodHandleAccessByte.java | 52 ++++++++++++++----- .../VarHandleTestMethodHandleAccessChar.java | 52 ++++++++++++++----- ...VarHandleTestMethodHandleAccessDouble.java | 52 ++++++++++++++----- .../VarHandleTestMethodHandleAccessFloat.java | 52 ++++++++++++++----- .../VarHandleTestMethodHandleAccessInt.java | 52 ++++++++++++++----- .../VarHandleTestMethodHandleAccessLong.java | 52 ++++++++++++++----- .../VarHandleTestMethodHandleAccessShort.java | 52 ++++++++++++++----- ...VarHandleTestMethodHandleAccessString.java | 52 ++++++++++++++----- .../X-VarHandleTestAccess.java.template | 12 +++++ ...X-VarHandleTestByteArrayView.java.template | 8 +++ ...HandleTestMethodHandleAccess.java.template | 52 ++++++++++++++----- 45 files changed, 951 insertions(+), 151 deletions(-) diff --git a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java index b3fa7c49a8d..98f638abe2d 100644 --- a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java +++ b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestBoolean.java @@ -43,7 +43,14 @@ public class JdkInternalMiscUnsafeAccessTestBoolean { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final jdk.internal.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class JdkInternalMiscUnsafeAccessTestBoolean { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static boolean static_v; boolean v; @@ -211,6 +228,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetBooleanPlain(base, offset, true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = UNSAFE.getBoolean(base, offset); @@ -228,6 +246,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetBooleanAcquire(base, offset, false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = UNSAFE.getBoolean(base, offset); @@ -245,6 +264,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetBooleanRelease(base, offset, true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = UNSAFE.getBoolean(base, offset); @@ -262,6 +282,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetBoolean(base, offset, false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = UNSAFE.getBoolean(base, offset); diff --git a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java index 0ce54ce877e..e149f6bd07b 100644 --- a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java +++ b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestByte.java @@ -43,7 +43,14 @@ public class JdkInternalMiscUnsafeAccessTestByte { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final jdk.internal.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class JdkInternalMiscUnsafeAccessTestByte { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static byte static_v; byte v; @@ -240,6 +257,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetBytePlain(base, offset, (byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = UNSAFE.getByte(base, offset); @@ -257,6 +275,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetByteAcquire(base, offset, (byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = UNSAFE.getByte(base, offset); @@ -274,6 +293,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetByteRelease(base, offset, (byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = UNSAFE.getByte(base, offset); @@ -291,6 +311,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetByte(base, offset, (byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = UNSAFE.getByte(base, offset); diff --git a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java index bcc8a481800..62d926b66a1 100644 --- a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java +++ b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestChar.java @@ -43,7 +43,14 @@ public class JdkInternalMiscUnsafeAccessTestChar { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final jdk.internal.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class JdkInternalMiscUnsafeAccessTestChar { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static char static_v; char v; @@ -258,6 +275,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetCharPlain(base, offset, '\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = UNSAFE.getChar(base, offset); @@ -275,6 +293,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetCharAcquire(base, offset, '\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = UNSAFE.getChar(base, offset); @@ -292,6 +311,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetCharRelease(base, offset, '\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = UNSAFE.getChar(base, offset); @@ -309,6 +329,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetChar(base, offset, '\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet char"); char x = UNSAFE.getChar(base, offset); diff --git a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java index ec68b3a52b9..2f90f0d7c7b 100644 --- a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java +++ b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestDouble.java @@ -43,7 +43,14 @@ public class JdkInternalMiscUnsafeAccessTestDouble { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final jdk.internal.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class JdkInternalMiscUnsafeAccessTestDouble { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static double static_v; double v; @@ -240,6 +257,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetDoublePlain(base, offset, 1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = UNSAFE.getDouble(base, offset); @@ -257,6 +275,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetDoubleAcquire(base, offset, 2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = UNSAFE.getDouble(base, offset); @@ -274,6 +293,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetDoubleRelease(base, offset, 1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = UNSAFE.getDouble(base, offset); @@ -291,6 +311,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetDouble(base, offset, 2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet double"); double x = UNSAFE.getDouble(base, offset); diff --git a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java index 73da36c8355..f0256e7815d 100644 --- a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java +++ b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestFloat.java @@ -43,7 +43,14 @@ public class JdkInternalMiscUnsafeAccessTestFloat { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final jdk.internal.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class JdkInternalMiscUnsafeAccessTestFloat { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static float static_v; float v; @@ -240,6 +257,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetFloatPlain(base, offset, 1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = UNSAFE.getFloat(base, offset); @@ -257,6 +275,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetFloatAcquire(base, offset, 2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = UNSAFE.getFloat(base, offset); @@ -274,6 +293,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetFloatRelease(base, offset, 1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = UNSAFE.getFloat(base, offset); @@ -291,6 +311,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetFloat(base, offset, 2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet float"); float x = UNSAFE.getFloat(base, offset); diff --git a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java index a62fede83d7..038cd2151b1 100644 --- a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java +++ b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestInt.java @@ -43,7 +43,14 @@ public class JdkInternalMiscUnsafeAccessTestInt { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final jdk.internal.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class JdkInternalMiscUnsafeAccessTestInt { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static int static_v; int v; @@ -258,6 +275,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetIntPlain(base, offset, 0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = UNSAFE.getInt(base, offset); @@ -275,6 +293,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetIntAcquire(base, offset, 0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = UNSAFE.getInt(base, offset); @@ -292,6 +311,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetIntRelease(base, offset, 0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = UNSAFE.getInt(base, offset); @@ -309,6 +329,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetInt(base, offset, 0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet int"); int x = UNSAFE.getInt(base, offset); diff --git a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java index f7ab52cb04e..cffec14ad72 100644 --- a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java +++ b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestLong.java @@ -43,7 +43,14 @@ public class JdkInternalMiscUnsafeAccessTestLong { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final jdk.internal.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class JdkInternalMiscUnsafeAccessTestLong { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static long static_v; long v; @@ -258,6 +275,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetLongPlain(base, offset, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = UNSAFE.getLong(base, offset); @@ -275,6 +293,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetLongAcquire(base, offset, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = UNSAFE.getLong(base, offset); @@ -292,6 +311,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetLongRelease(base, offset, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = UNSAFE.getLong(base, offset); @@ -309,6 +329,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetLong(base, offset, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet long"); long x = UNSAFE.getLong(base, offset); diff --git a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java index 57395802886..0c74c295e21 100644 --- a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java +++ b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestObject.java @@ -43,7 +43,14 @@ public class JdkInternalMiscUnsafeAccessTestObject { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final jdk.internal.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class JdkInternalMiscUnsafeAccessTestObject { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static Object static_v; Object v; @@ -211,6 +228,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetReferencePlain(base, offset, "foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain Object"); Object x = UNSAFE.getReference(base, offset); @@ -228,6 +246,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetReferenceAcquire(base, offset, "bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire Object"); Object x = UNSAFE.getReference(base, offset); @@ -245,6 +264,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetReferenceRelease(base, offset, "foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease Object"); Object x = UNSAFE.getReference(base, offset); @@ -262,6 +282,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetReference(base, offset, "bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet Object"); Object x = UNSAFE.getReference(base, offset); diff --git a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java index 5b3b006308b..770677a98d3 100644 --- a/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java +++ b/test/hotspot/jtreg/compiler/unsafe/JdkInternalMiscUnsafeAccessTestShort.java @@ -43,7 +43,14 @@ public class JdkInternalMiscUnsafeAccessTestShort { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final jdk.internal.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class JdkInternalMiscUnsafeAccessTestShort { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static short static_v; short v; @@ -258,6 +275,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetShortPlain(base, offset, (short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = UNSAFE.getShort(base, offset); @@ -275,6 +293,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetShortAcquire(base, offset, (short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = UNSAFE.getShort(base, offset); @@ -292,6 +311,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetShortRelease(base, offset, (short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = UNSAFE.getShort(base, offset); @@ -309,6 +329,7 @@ static void testAccess(Object base, long offset) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSetShort(base, offset, (short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet short"); short x = UNSAFE.getShort(base, offset); diff --git a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java index 6de29f5b39c..c176277d2ba 100644 --- a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java +++ b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestBoolean.java @@ -43,7 +43,14 @@ public class SunMiscUnsafeAccessTestBoolean { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final sun.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class SunMiscUnsafeAccessTestBoolean { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static boolean static_v; boolean v; diff --git a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestByte.java b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestByte.java index 87aa8c66a57..b205b1d3376 100644 --- a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestByte.java +++ b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestByte.java @@ -43,7 +43,14 @@ public class SunMiscUnsafeAccessTestByte { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final sun.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class SunMiscUnsafeAccessTestByte { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static byte static_v; byte v; diff --git a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestChar.java b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestChar.java index 8e10d4334e4..114ed7e9b5a 100644 --- a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestChar.java +++ b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestChar.java @@ -43,7 +43,14 @@ public class SunMiscUnsafeAccessTestChar { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final sun.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class SunMiscUnsafeAccessTestChar { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static char static_v; char v; diff --git a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java index 878336db8a1..d813ea73e70 100644 --- a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java +++ b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestDouble.java @@ -43,7 +43,14 @@ public class SunMiscUnsafeAccessTestDouble { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final sun.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class SunMiscUnsafeAccessTestDouble { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static double static_v; double v; diff --git a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java index 616919f09f4..f0482c82637 100644 --- a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java +++ b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestFloat.java @@ -43,7 +43,14 @@ public class SunMiscUnsafeAccessTestFloat { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final sun.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class SunMiscUnsafeAccessTestFloat { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static float static_v; float v; diff --git a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestInt.java b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestInt.java index 05e9a467a89..9326539f4ef 100644 --- a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestInt.java +++ b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestInt.java @@ -43,7 +43,14 @@ public class SunMiscUnsafeAccessTestInt { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final sun.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class SunMiscUnsafeAccessTestInt { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static int static_v; int v; diff --git a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestLong.java b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestLong.java index 38b0a83296a..30bc9551dd5 100644 --- a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestLong.java +++ b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestLong.java @@ -43,7 +43,14 @@ public class SunMiscUnsafeAccessTestLong { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final sun.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class SunMiscUnsafeAccessTestLong { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static long static_v; long v; diff --git a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestObject.java b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestObject.java index 8782995957b..add15ff77fd 100644 --- a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestObject.java +++ b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestObject.java @@ -43,7 +43,14 @@ public class SunMiscUnsafeAccessTestObject { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final sun.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class SunMiscUnsafeAccessTestObject { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static Object static_v; Object v; diff --git a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestShort.java b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestShort.java index c16761daaac..4ea81f026e7 100644 --- a/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestShort.java +++ b/test/hotspot/jtreg/compiler/unsafe/SunMiscUnsafeAccessTestShort.java @@ -43,7 +43,14 @@ public class SunMiscUnsafeAccessTestShort { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final sun.misc.Unsafe UNSAFE; @@ -86,6 +93,16 @@ public class SunMiscUnsafeAccessTestShort { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static short static_v; short v; diff --git a/test/hotspot/jtreg/compiler/unsafe/X-UnsafeAccessTest.java.template b/test/hotspot/jtreg/compiler/unsafe/X-UnsafeAccessTest.java.template index b4dc38376a6..2fc22fa360a 100644 --- a/test/hotspot/jtreg/compiler/unsafe/X-UnsafeAccessTest.java.template +++ b/test/hotspot/jtreg/compiler/unsafe/X-UnsafeAccessTest.java.template @@ -47,7 +47,14 @@ import static org.testng.Assert.*; public class $Qualifier$UnsafeAccessTest$Type$ { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); static final $package$.Unsafe UNSAFE; @@ -90,6 +97,16 @@ public class $Qualifier$UnsafeAccessTest$Type$ { ARRAY_SHIFT = 31 - Integer.numberOfLeadingZeros(ascale); } + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } + static $type$ static_v; $type$ v; @@ -302,6 +319,7 @@ public class $Qualifier$UnsafeAccessTest$Type$ { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSet$MethodAffix$Plain(base, offset, $value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = UNSAFE.get$MethodAffix$(base, offset); @@ -319,6 +337,7 @@ public class $Qualifier$UnsafeAccessTest$Type$ { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSet$MethodAffix$Acquire(base, offset, $value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = UNSAFE.get$MethodAffix$(base, offset); @@ -336,6 +355,7 @@ public class $Qualifier$UnsafeAccessTest$Type$ { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSet$MethodAffix$Release(base, offset, $value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = UNSAFE.get$MethodAffix$(base, offset); @@ -353,6 +373,7 @@ public class $Qualifier$UnsafeAccessTest$Type$ { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = UNSAFE.weakCompareAndSet$MethodAffix$(base, offset, $value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = UNSAFE.get$MethodAffix$(base, offset); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java index 855ccc9f941..81978c7a79c 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleBaseTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2022, 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 @@ -40,7 +40,14 @@ abstract class VarHandleBaseTest { static final int ITERS = Integer.getInteger("iters", 1); - static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 10); + + // More resilience for Weak* tests. These operations may spuriously + // fail, and so we do several attempts with delay on failure. + // Be mindful of worst-case total time on test, which would be at + // roughly (delay*attempts) milliseconds. + // + static final int WEAK_ATTEMPTS = Integer.getInteger("weakAttempts", 100); + static final int WEAK_DELAY_MS = Math.max(1, Integer.getInteger("weakDelay", 1)); interface ThrowingRunnable { void run() throws Throwable; @@ -498,4 +505,14 @@ static void testTypes(VarHandle vh) { assertEquals(mt.parameterType(mt.parameterCount() - 1), vh.varType()); } } + + static void weakDelay() { + try { + if (WEAK_DELAY_MS > 0) { + Thread.sleep(WEAK_DELAY_MS); + } + } catch (InterruptedException ie) { + // Do nothing. + } + } } diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java index 1faf06f110c..58fca6b750a 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessBoolean.java @@ -505,6 +505,7 @@ static void testInstanceField(VarHandleTestAccessBoolean recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(recv, true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) vh.get(recv); @@ -522,6 +523,7 @@ static void testInstanceField(VarHandleTestAccessBoolean recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(recv, false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) vh.get(recv); @@ -539,6 +541,7 @@ static void testInstanceField(VarHandleTestAccessBoolean recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(recv, true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) vh.get(recv); @@ -556,6 +559,7 @@ static void testInstanceField(VarHandleTestAccessBoolean recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(recv, false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) vh.get(recv); @@ -793,6 +797,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) vh.get(); @@ -810,6 +815,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) vh.get(); @@ -827,6 +833,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) vh.get(); @@ -844,6 +851,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) vh.get(); @@ -1084,6 +1092,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) vh.get(array, i); @@ -1101,6 +1110,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) vh.get(array, i); @@ -1118,6 +1128,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) vh.get(array, i); @@ -1135,6 +1146,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java index b508d31307b..f51c6886aac 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessByte.java @@ -483,6 +483,7 @@ static void testInstanceField(VarHandleTestAccessByte recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(recv, (byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) vh.get(recv); @@ -500,6 +501,7 @@ static void testInstanceField(VarHandleTestAccessByte recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(recv, (byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) vh.get(recv); @@ -517,6 +519,7 @@ static void testInstanceField(VarHandleTestAccessByte recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(recv, (byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) vh.get(recv); @@ -534,6 +537,7 @@ static void testInstanceField(VarHandleTestAccessByte recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(recv, (byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) vh.get(recv); @@ -787,6 +791,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain((byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) vh.get(); @@ -804,6 +809,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire((byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) vh.get(); @@ -821,6 +827,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease((byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) vh.get(); @@ -838,6 +845,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet((byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) vh.get(); @@ -1094,6 +1102,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, (byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) vh.get(array, i); @@ -1111,6 +1120,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, (byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) vh.get(array, i); @@ -1128,6 +1138,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, (byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) vh.get(array, i); @@ -1145,6 +1156,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, (byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java index 133a4e9a992..3a083df78b1 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessChar.java @@ -483,6 +483,7 @@ static void testInstanceField(VarHandleTestAccessChar recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(recv, '\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) vh.get(recv); @@ -500,6 +501,7 @@ static void testInstanceField(VarHandleTestAccessChar recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(recv, '\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) vh.get(recv); @@ -517,6 +519,7 @@ static void testInstanceField(VarHandleTestAccessChar recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(recv, '\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) vh.get(recv); @@ -534,6 +537,7 @@ static void testInstanceField(VarHandleTestAccessChar recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(recv, '\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) vh.get(recv); @@ -787,6 +791,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain('\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) vh.get(); @@ -804,6 +809,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire('\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) vh.get(); @@ -821,6 +827,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease('\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) vh.get(); @@ -838,6 +845,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet('\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) vh.get(); @@ -1094,6 +1102,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, '\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) vh.get(array, i); @@ -1111,6 +1120,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, '\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) vh.get(array, i); @@ -1128,6 +1138,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, '\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) vh.get(array, i); @@ -1145,6 +1156,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, '\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java index c736569f1d3..c3e129e9232 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessDouble.java @@ -553,6 +553,7 @@ static void testInstanceField(VarHandleTestAccessDouble recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(recv, 1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) vh.get(recv); @@ -570,6 +571,7 @@ static void testInstanceField(VarHandleTestAccessDouble recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(recv, 2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) vh.get(recv); @@ -587,6 +589,7 @@ static void testInstanceField(VarHandleTestAccessDouble recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(recv, 1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) vh.get(recv); @@ -604,6 +607,7 @@ static void testInstanceField(VarHandleTestAccessDouble recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(recv, 2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) vh.get(recv); @@ -809,6 +813,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) vh.get(); @@ -826,6 +831,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) vh.get(); @@ -843,6 +849,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) vh.get(); @@ -860,6 +867,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) vh.get(); @@ -1068,6 +1076,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, 1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) vh.get(array, i); @@ -1085,6 +1094,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, 2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) vh.get(array, i); @@ -1102,6 +1112,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, 1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) vh.get(array, i); @@ -1119,6 +1130,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, 2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java index 92a4bb24c19..1b692c72bd0 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessFloat.java @@ -553,6 +553,7 @@ static void testInstanceField(VarHandleTestAccessFloat recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(recv, 1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) vh.get(recv); @@ -570,6 +571,7 @@ static void testInstanceField(VarHandleTestAccessFloat recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(recv, 2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) vh.get(recv); @@ -587,6 +589,7 @@ static void testInstanceField(VarHandleTestAccessFloat recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(recv, 1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) vh.get(recv); @@ -604,6 +607,7 @@ static void testInstanceField(VarHandleTestAccessFloat recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(recv, 2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) vh.get(recv); @@ -809,6 +813,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) vh.get(); @@ -826,6 +831,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) vh.get(); @@ -843,6 +849,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) vh.get(); @@ -860,6 +867,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) vh.get(); @@ -1068,6 +1076,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, 1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) vh.get(array, i); @@ -1085,6 +1094,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, 2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) vh.get(array, i); @@ -1102,6 +1112,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, 1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) vh.get(array, i); @@ -1119,6 +1130,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, 2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java index 221ed534eb4..c16546c4789 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessInt.java @@ -483,6 +483,7 @@ static void testInstanceField(VarHandleTestAccessInt recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(recv, 0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) vh.get(recv); @@ -500,6 +501,7 @@ static void testInstanceField(VarHandleTestAccessInt recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(recv, 0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) vh.get(recv); @@ -517,6 +519,7 @@ static void testInstanceField(VarHandleTestAccessInt recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(recv, 0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) vh.get(recv); @@ -534,6 +537,7 @@ static void testInstanceField(VarHandleTestAccessInt recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(recv, 0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) vh.get(recv); @@ -787,6 +791,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) vh.get(); @@ -804,6 +809,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) vh.get(); @@ -821,6 +827,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) vh.get(); @@ -838,6 +845,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) vh.get(); @@ -1094,6 +1102,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, 0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) vh.get(array, i); @@ -1111,6 +1120,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, 0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) vh.get(array, i); @@ -1128,6 +1138,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, 0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) vh.get(array, i); @@ -1145,6 +1156,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, 0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java index c0dc5b090c2..db7777982d2 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessLong.java @@ -483,6 +483,7 @@ static void testInstanceField(VarHandleTestAccessLong recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(recv, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) vh.get(recv); @@ -500,6 +501,7 @@ static void testInstanceField(VarHandleTestAccessLong recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(recv, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) vh.get(recv); @@ -517,6 +519,7 @@ static void testInstanceField(VarHandleTestAccessLong recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(recv, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) vh.get(recv); @@ -534,6 +537,7 @@ static void testInstanceField(VarHandleTestAccessLong recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(recv, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) vh.get(recv); @@ -787,6 +791,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) vh.get(); @@ -804,6 +809,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) vh.get(); @@ -821,6 +827,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) vh.get(); @@ -838,6 +845,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) vh.get(); @@ -1094,6 +1102,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) vh.get(array, i); @@ -1111,6 +1120,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) vh.get(array, i); @@ -1128,6 +1138,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) vh.get(array, i); @@ -1145,6 +1156,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java index 3282edfdd5c..8598d1c9ecf 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessShort.java @@ -483,6 +483,7 @@ static void testInstanceField(VarHandleTestAccessShort recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(recv, (short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) vh.get(recv); @@ -500,6 +501,7 @@ static void testInstanceField(VarHandleTestAccessShort recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(recv, (short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) vh.get(recv); @@ -517,6 +519,7 @@ static void testInstanceField(VarHandleTestAccessShort recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(recv, (short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) vh.get(recv); @@ -534,6 +537,7 @@ static void testInstanceField(VarHandleTestAccessShort recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(recv, (short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) vh.get(recv); @@ -787,6 +791,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain((short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) vh.get(); @@ -804,6 +809,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire((short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) vh.get(); @@ -821,6 +827,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease((short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) vh.get(); @@ -838,6 +845,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet((short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) vh.get(); @@ -1094,6 +1102,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, (short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) vh.get(array, i); @@ -1111,6 +1120,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, (short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) vh.get(array, i); @@ -1128,6 +1138,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, (short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) vh.get(array, i); @@ -1145,6 +1156,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, (short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java index 1d6173e8aa1..d84395bbede 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestAccessString.java @@ -582,6 +582,7 @@ static void testInstanceField(VarHandleTestAccessString recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(recv, "foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) vh.get(recv); @@ -599,6 +600,7 @@ static void testInstanceField(VarHandleTestAccessString recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(recv, "bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) vh.get(recv); @@ -616,6 +618,7 @@ static void testInstanceField(VarHandleTestAccessString recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(recv, "foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) vh.get(recv); @@ -633,6 +636,7 @@ static void testInstanceField(VarHandleTestAccessString recv, VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(recv, "bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) vh.get(recv); @@ -822,6 +826,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain("foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) vh.get(); @@ -839,6 +844,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire("bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) vh.get(); @@ -856,6 +862,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease("foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) vh.get(); @@ -873,6 +880,7 @@ static void testStaticField(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet("bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) vh.get(); @@ -1065,6 +1073,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, "foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) vh.get(array, i); @@ -1082,6 +1091,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, "bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) vh.get(array, i); @@ -1099,6 +1109,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, "foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) vh.get(array, i); @@ -1116,6 +1127,7 @@ static void testArray(VarHandle vh) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, "bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java index 30d7c0e2a92..a0570c62d96 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsDouble.java @@ -1081,6 +1081,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) vh.get(array, i); @@ -1098,6 +1099,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) vh.get(array, i); @@ -1115,6 +1117,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) vh.get(array, i); @@ -1132,6 +1135,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) vh.get(array, i); @@ -1282,6 +1286,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) vh.get(array, i); @@ -1299,6 +1304,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) vh.get(array, i); @@ -1316,6 +1322,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) vh.get(array, i); @@ -1333,6 +1340,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java index d74dd899727..ba82ac77e0a 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsFloat.java @@ -1081,6 +1081,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) vh.get(array, i); @@ -1098,6 +1099,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) vh.get(array, i); @@ -1115,6 +1117,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) vh.get(array, i); @@ -1132,6 +1135,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) vh.get(array, i); @@ -1282,6 +1286,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) vh.get(array, i); @@ -1299,6 +1304,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) vh.get(array, i); @@ -1316,6 +1322,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) vh.get(array, i); @@ -1333,6 +1340,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java index 7f78a128ecc..bc59c082d28 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsInt.java @@ -1265,6 +1265,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) vh.get(array, i); @@ -1282,6 +1283,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) vh.get(array, i); @@ -1299,6 +1301,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) vh.get(array, i); @@ -1316,6 +1319,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) vh.get(array, i); @@ -1576,6 +1580,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) vh.get(array, i); @@ -1593,6 +1598,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) vh.get(array, i); @@ -1610,6 +1616,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) vh.get(array, i); @@ -1627,6 +1634,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java index 6ee5da8040d..4b96f01bd2d 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestByteArrayAsLong.java @@ -1265,6 +1265,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) vh.get(array, i); @@ -1282,6 +1283,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) vh.get(array, i); @@ -1299,6 +1301,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) vh.get(array, i); @@ -1316,6 +1319,7 @@ static void testArrayReadWrite(ByteArraySource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) vh.get(array, i); @@ -1576,6 +1580,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) vh.get(array, i); @@ -1593,6 +1598,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) vh.get(array, i); @@ -1610,6 +1616,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) vh.get(array, i); @@ -1627,6 +1634,7 @@ static void testArrayReadWrite(ByteBufferSource bs, VarHandleSource vhs) { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java index 38663a879b9..2177d2bc11c 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessBoolean.java @@ -30,6 +30,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -208,9 +209,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessBoolean recv, Handl } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, true, false); + success = (boolean) mh.invokeExact(recv, true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -225,9 +228,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessBoolean recv, Handl } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, false, true); + success = (boolean) mh.invokeExact(recv, false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -242,9 +247,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessBoolean recv, Handl } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, true, false); + success = (boolean) mh.invokeExact(recv, true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -260,8 +267,10 @@ static void testInstanceField(VarHandleTestMethodHandleAccessBoolean recv, Handl { boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, false, true); + success = (boolean) mh.invokeExact(recv, false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -470,9 +479,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(true, false); + success = (boolean) mh.invokeExact(true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); @@ -487,9 +498,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(false, true); + success = (boolean) mh.invokeExact(false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); @@ -497,16 +510,19 @@ static void testStaticField(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(false, false); + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact(false, false); assertEquals(success, false, "failing weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, true, "failing weakCompareAndSetAcquire boolean value"); } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(true, false); + success = (boolean) mh.invokeExact(true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); @@ -521,9 +537,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(false, true); + success = (boolean) mh.invokeExact(false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(); @@ -757,9 +775,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, true, false); + success = (boolean) mh.invokeExact(array, i, true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -774,9 +794,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, false, true); + success = (boolean) mh.invokeExact(array, i, false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -791,9 +813,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, true, false); + success = (boolean) mh.invokeExact(array, i, true, false); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -808,9 +832,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, false, true); + success = (boolean) mh.invokeExact(array, i, false, true); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet boolean"); boolean x = (boolean) hs.get(TestAccessMode.GET).invokeExact(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java index ef53c05cca8..7ab5d14755f 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessByte.java @@ -30,6 +30,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -208,9 +209,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessByte recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, (byte)0x01, (byte)0x23); + success = (boolean) mh.invokeExact(recv, (byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -225,9 +228,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessByte recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, (byte)0x23, (byte)0x01); + success = (boolean) mh.invokeExact(recv, (byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -242,9 +247,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessByte recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, (byte)0x01, (byte)0x23); + success = (boolean) mh.invokeExact(recv, (byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -260,8 +267,10 @@ static void testInstanceField(VarHandleTestMethodHandleAccessByte recv, Handles { boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, (byte)0x23, (byte)0x01); + success = (boolean) mh.invokeExact(recv, (byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -492,9 +501,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact((byte)0x01, (byte)0x23); + success = (boolean) mh.invokeExact((byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); @@ -509,9 +520,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact((byte)0x23, (byte)0x01); + success = (boolean) mh.invokeExact((byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); @@ -519,16 +532,19 @@ static void testStaticField(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact((byte)0x23, (byte)0x45); + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact((byte)0x23, (byte)0x45); assertEquals(success, false, "failing weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, (byte)0x01, "failing weakCompareAndSetAcquire byte value"); } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact((byte)0x01, (byte)0x23); + success = (boolean) mh.invokeExact((byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); @@ -543,9 +559,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact((byte)0x23, (byte)0x01); + success = (boolean) mh.invokeExact((byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(); @@ -801,9 +819,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, (byte)0x01, (byte)0x23); + success = (boolean) mh.invokeExact(array, i, (byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -818,9 +838,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, (byte)0x23, (byte)0x01); + success = (boolean) mh.invokeExact(array, i, (byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -835,9 +857,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, (byte)0x01, (byte)0x23); + success = (boolean) mh.invokeExact(array, i, (byte)0x01, (byte)0x23); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -852,9 +876,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, (byte)0x23, (byte)0x01); + success = (boolean) mh.invokeExact(array, i, (byte)0x23, (byte)0x01); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet byte"); byte x = (byte) hs.get(TestAccessMode.GET).invokeExact(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java index 40a26f15b46..bcdbf410750 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessChar.java @@ -30,6 +30,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -208,9 +209,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessChar recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, '\u0123', '\u4567'); + success = (boolean) mh.invokeExact(recv, '\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -225,9 +228,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessChar recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, '\u4567', '\u0123'); + success = (boolean) mh.invokeExact(recv, '\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -242,9 +247,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessChar recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, '\u0123', '\u4567'); + success = (boolean) mh.invokeExact(recv, '\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -260,8 +267,10 @@ static void testInstanceField(VarHandleTestMethodHandleAccessChar recv, Handles { boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, '\u4567', '\u0123'); + success = (boolean) mh.invokeExact(recv, '\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -492,9 +501,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact('\u0123', '\u4567'); + success = (boolean) mh.invokeExact('\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); @@ -509,9 +520,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact('\u4567', '\u0123'); + success = (boolean) mh.invokeExact('\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); @@ -519,16 +532,19 @@ static void testStaticField(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact('\u4567', '\u89AB'); + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact('\u4567', '\u89AB'); assertEquals(success, false, "failing weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, '\u0123', "failing weakCompareAndSetAcquire char value"); } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact('\u0123', '\u4567'); + success = (boolean) mh.invokeExact('\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); @@ -543,9 +559,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact('\u4567', '\u0123'); + success = (boolean) mh.invokeExact('\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(); @@ -801,9 +819,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, '\u0123', '\u4567'); + success = (boolean) mh.invokeExact(array, i, '\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -818,9 +838,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, '\u4567', '\u0123'); + success = (boolean) mh.invokeExact(array, i, '\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -835,9 +857,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, '\u0123', '\u4567'); + success = (boolean) mh.invokeExact(array, i, '\u0123', '\u4567'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -852,9 +876,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, '\u4567', '\u0123'); + success = (boolean) mh.invokeExact(array, i, '\u4567', '\u0123'); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet char"); char x = (char) hs.get(TestAccessMode.GET).invokeExact(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java index d2f68e8308e..b4fc64d553f 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessDouble.java @@ -30,6 +30,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -208,9 +209,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessDouble recv, Handle } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, 1.0d, 2.0d); + success = (boolean) mh.invokeExact(recv, 1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -225,9 +228,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessDouble recv, Handle } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, 2.0d, 1.0d); + success = (boolean) mh.invokeExact(recv, 2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -242,9 +247,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessDouble recv, Handle } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, 1.0d, 2.0d); + success = (boolean) mh.invokeExact(recv, 1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -260,8 +267,10 @@ static void testInstanceField(VarHandleTestMethodHandleAccessDouble recv, Handle { boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, 2.0d, 1.0d); + success = (boolean) mh.invokeExact(recv, 2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -414,9 +423,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(1.0d, 2.0d); + success = (boolean) mh.invokeExact(1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); @@ -431,9 +442,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(2.0d, 1.0d); + success = (boolean) mh.invokeExact(2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); @@ -441,16 +454,19 @@ static void testStaticField(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(2.0d, 3.0d); + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact(2.0d, 3.0d); assertEquals(success, false, "failing weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, 1.0d, "failing weakCompareAndSetAcquire double value"); } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(1.0d, 2.0d); + success = (boolean) mh.invokeExact(1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); @@ -465,9 +481,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(2.0d, 1.0d); + success = (boolean) mh.invokeExact(2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(); @@ -645,9 +663,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, 1.0d, 2.0d); + success = (boolean) mh.invokeExact(array, i, 1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -662,9 +682,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 2.0d, 1.0d); + success = (boolean) mh.invokeExact(array, i, 2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -679,9 +701,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, 1.0d, 2.0d); + success = (boolean) mh.invokeExact(array, i, 1.0d, 2.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -696,9 +720,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, 2.0d, 1.0d); + success = (boolean) mh.invokeExact(array, i, 2.0d, 1.0d); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet double"); double x = (double) hs.get(TestAccessMode.GET).invokeExact(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java index 24979a3fa7c..d8e949a10ed 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessFloat.java @@ -30,6 +30,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -208,9 +209,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessFloat recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, 1.0f, 2.0f); + success = (boolean) mh.invokeExact(recv, 1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -225,9 +228,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessFloat recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, 2.0f, 1.0f); + success = (boolean) mh.invokeExact(recv, 2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -242,9 +247,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessFloat recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, 1.0f, 2.0f); + success = (boolean) mh.invokeExact(recv, 1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -260,8 +267,10 @@ static void testInstanceField(VarHandleTestMethodHandleAccessFloat recv, Handles { boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, 2.0f, 1.0f); + success = (boolean) mh.invokeExact(recv, 2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -414,9 +423,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(1.0f, 2.0f); + success = (boolean) mh.invokeExact(1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); @@ -431,9 +442,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(2.0f, 1.0f); + success = (boolean) mh.invokeExact(2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); @@ -441,16 +454,19 @@ static void testStaticField(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(2.0f, 3.0f); + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact(2.0f, 3.0f); assertEquals(success, false, "failing weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, 1.0f, "failing weakCompareAndSetAcquire float value"); } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(1.0f, 2.0f); + success = (boolean) mh.invokeExact(1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); @@ -465,9 +481,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(2.0f, 1.0f); + success = (boolean) mh.invokeExact(2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(); @@ -645,9 +663,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, 1.0f, 2.0f); + success = (boolean) mh.invokeExact(array, i, 1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -662,9 +682,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 2.0f, 1.0f); + success = (boolean) mh.invokeExact(array, i, 2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -679,9 +701,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, 1.0f, 2.0f); + success = (boolean) mh.invokeExact(array, i, 1.0f, 2.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -696,9 +720,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, 2.0f, 1.0f); + success = (boolean) mh.invokeExact(array, i, 2.0f, 1.0f); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet float"); float x = (float) hs.get(TestAccessMode.GET).invokeExact(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java index 03e63808be6..824a14e2157 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessInt.java @@ -30,6 +30,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -208,9 +209,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessInt recv, Handles h } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, 0x01234567, 0x89ABCDEF); + success = (boolean) mh.invokeExact(recv, 0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -225,9 +228,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessInt recv, Handles h } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, 0x89ABCDEF, 0x01234567); + success = (boolean) mh.invokeExact(recv, 0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -242,9 +247,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessInt recv, Handles h } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, 0x01234567, 0x89ABCDEF); + success = (boolean) mh.invokeExact(recv, 0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -260,8 +267,10 @@ static void testInstanceField(VarHandleTestMethodHandleAccessInt recv, Handles h { boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, 0x89ABCDEF, 0x01234567); + success = (boolean) mh.invokeExact(recv, 0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -492,9 +501,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(0x01234567, 0x89ABCDEF); + success = (boolean) mh.invokeExact(0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); @@ -509,9 +520,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(0x89ABCDEF, 0x01234567); + success = (boolean) mh.invokeExact(0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); @@ -519,16 +532,19 @@ static void testStaticField(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(0x89ABCDEF, 0xCAFEBABE); + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact(0x89ABCDEF, 0xCAFEBABE); assertEquals(success, false, "failing weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, 0x01234567, "failing weakCompareAndSetAcquire int value"); } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(0x01234567, 0x89ABCDEF); + success = (boolean) mh.invokeExact(0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); @@ -543,9 +559,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(0x89ABCDEF, 0x01234567); + success = (boolean) mh.invokeExact(0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(); @@ -801,9 +819,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, 0x01234567, 0x89ABCDEF); + success = (boolean) mh.invokeExact(array, i, 0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -818,9 +838,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 0x89ABCDEF, 0x01234567); + success = (boolean) mh.invokeExact(array, i, 0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -835,9 +857,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, 0x01234567, 0x89ABCDEF); + success = (boolean) mh.invokeExact(array, i, 0x01234567, 0x89ABCDEF); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -852,9 +876,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, 0x89ABCDEF, 0x01234567); + success = (boolean) mh.invokeExact(array, i, 0x89ABCDEF, 0x01234567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet int"); int x = (int) hs.get(TestAccessMode.GET).invokeExact(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java index bf850b75d94..ebf80402b38 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessLong.java @@ -30,6 +30,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -208,9 +209,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessLong recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + success = (boolean) mh.invokeExact(recv, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -225,9 +228,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessLong recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + success = (boolean) mh.invokeExact(recv, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -242,9 +247,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessLong recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + success = (boolean) mh.invokeExact(recv, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -260,8 +267,10 @@ static void testInstanceField(VarHandleTestMethodHandleAccessLong recv, Handles { boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + success = (boolean) mh.invokeExact(recv, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -492,9 +501,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + success = (boolean) mh.invokeExact(0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); @@ -509,9 +520,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + success = (boolean) mh.invokeExact(0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); @@ -519,16 +532,19 @@ static void testStaticField(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact(0xCAFEBABECAFEBABEL, 0xDEADBEEFDEADBEEFL); assertEquals(success, false, "failing weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, 0x0123456789ABCDEFL, "failing weakCompareAndSetAcquire long value"); } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + success = (boolean) mh.invokeExact(0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); @@ -543,9 +559,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + success = (boolean) mh.invokeExact(0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(); @@ -801,9 +819,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + success = (boolean) mh.invokeExact(array, i, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -818,9 +838,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + success = (boolean) mh.invokeExact(array, i, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -835,9 +857,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + success = (boolean) mh.invokeExact(array, i, 0x0123456789ABCDEFL, 0xCAFEBABECAFEBABEL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -852,9 +876,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + success = (boolean) mh.invokeExact(array, i, 0xCAFEBABECAFEBABEL, 0x0123456789ABCDEFL); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet long"); long x = (long) hs.get(TestAccessMode.GET).invokeExact(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java index 7bfafe91483..63189b1e0a8 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessShort.java @@ -30,6 +30,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -208,9 +209,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessShort recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, (short)0x0123, (short)0x4567); + success = (boolean) mh.invokeExact(recv, (short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -225,9 +228,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessShort recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, (short)0x4567, (short)0x0123); + success = (boolean) mh.invokeExact(recv, (short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -242,9 +247,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessShort recv, Handles } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, (short)0x0123, (short)0x4567); + success = (boolean) mh.invokeExact(recv, (short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -260,8 +267,10 @@ static void testInstanceField(VarHandleTestMethodHandleAccessShort recv, Handles { boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, (short)0x4567, (short)0x0123); + success = (boolean) mh.invokeExact(recv, (short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -492,9 +501,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact((short)0x0123, (short)0x4567); + success = (boolean) mh.invokeExact((short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); @@ -509,9 +520,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact((short)0x4567, (short)0x0123); + success = (boolean) mh.invokeExact((short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); @@ -519,16 +532,19 @@ static void testStaticField(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact((short)0x4567, (short)0x89AB); + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact((short)0x4567, (short)0x89AB); assertEquals(success, false, "failing weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, (short)0x0123, "failing weakCompareAndSetAcquire short value"); } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact((short)0x0123, (short)0x4567); + success = (boolean) mh.invokeExact((short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); @@ -543,9 +559,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact((short)0x4567, (short)0x0123); + success = (boolean) mh.invokeExact((short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(); @@ -801,9 +819,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, (short)0x0123, (short)0x4567); + success = (boolean) mh.invokeExact(array, i, (short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -818,9 +838,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, (short)0x4567, (short)0x0123); + success = (boolean) mh.invokeExact(array, i, (short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -835,9 +857,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, (short)0x0123, (short)0x4567); + success = (boolean) mh.invokeExact(array, i, (short)0x0123, (short)0x4567); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -852,9 +876,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, (short)0x4567, (short)0x0123); + success = (boolean) mh.invokeExact(array, i, (short)0x4567, (short)0x0123); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet short"); short x = (short) hs.get(TestAccessMode.GET).invokeExact(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java index c1ba3af8c56..0f7ebc5219f 100644 --- a/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java +++ b/test/jdk/java/lang/invoke/VarHandles/VarHandleTestMethodHandleAccessString.java @@ -30,6 +30,7 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -208,9 +209,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessString recv, Handle } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, "foo", "bar"); + success = (boolean) mh.invokeExact(recv, "foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -225,9 +228,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessString recv, Handle } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, "bar", "foo"); + success = (boolean) mh.invokeExact(recv, "bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -242,9 +247,11 @@ static void testInstanceField(VarHandleTestMethodHandleAccessString recv, Handle } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, "foo", "bar"); + success = (boolean) mh.invokeExact(recv, "foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -260,8 +267,10 @@ static void testInstanceField(VarHandleTestMethodHandleAccessString recv, Handle { boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, "bar", "foo"); + success = (boolean) mh.invokeExact(recv, "bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -392,9 +401,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact("foo", "bar"); + success = (boolean) mh.invokeExact("foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); @@ -409,9 +420,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact("bar", "foo"); + success = (boolean) mh.invokeExact("bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); @@ -419,16 +432,19 @@ static void testStaticField(Handles hs) throws Throwable { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact("bar", "baz"); + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact("bar", "baz"); assertEquals(success, false, "failing weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, "foo", "failing weakCompareAndSetAcquire String value"); } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact("foo", "bar"); + success = (boolean) mh.invokeExact("foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); @@ -443,9 +459,11 @@ static void testStaticField(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact("bar", "foo"); + success = (boolean) mh.invokeExact("bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(); @@ -601,9 +619,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, "foo", "bar"); + success = (boolean) mh.invokeExact(array, i, "foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -618,9 +638,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, "bar", "foo"); + success = (boolean) mh.invokeExact(array, i, "bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -635,9 +657,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, "foo", "bar"); + success = (boolean) mh.invokeExact(array, i, "foo", "bar"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -652,9 +676,11 @@ static void testArray(Handles hs) throws Throwable { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, "bar", "foo"); + success = (boolean) mh.invokeExact(array, i, "bar", "foo"); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet String"); String x = (String) hs.get(TestAccessMode.GET).invokeExact(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template index 0802001f179..4fa8fa8e747 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestAccess.java.template @@ -725,6 +725,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(recv, $value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(recv); @@ -742,6 +743,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(recv, $value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(recv); @@ -759,6 +761,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(recv, $value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(recv); @@ -776,6 +779,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(recv, $value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(recv); @@ -1130,6 +1134,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain($value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(); @@ -1147,6 +1152,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire($value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(); @@ -1164,6 +1170,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease($value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(); @@ -1181,6 +1188,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet($value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(); @@ -1538,6 +1546,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, $value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(array, i); @@ -1555,6 +1564,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, $value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(array, i); @@ -1572,6 +1582,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, $value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(array, i); @@ -1589,6 +1600,7 @@ public class VarHandleTestAccess$Type$ extends VarHandleBaseTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, $value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template index 3880de14324..6770c7b2ed3 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestByteArrayView.java.template @@ -1626,6 +1626,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(array, i); @@ -1643,6 +1644,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(array, i); @@ -1660,6 +1662,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(array, i); @@ -1677,6 +1680,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); @@ -1943,6 +1947,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetPlain(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) vh.get(array, i); @@ -1960,6 +1965,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetAcquire(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) vh.get(array, i); @@ -1977,6 +1983,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSetRelease(array, i, VALUE_1, VALUE_2); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) vh.get(array, i); @@ -1994,6 +2001,7 @@ public class VarHandleTestByteArrayAs$Type$ extends VarHandleBaseByteArrayTest { boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { success = vh.weakCompareAndSet(array, i, VALUE_2, VALUE_1); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) vh.get(array, i); diff --git a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template index 9044f990e7b..98ee4a13783 100644 --- a/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template +++ b/test/jdk/java/lang/invoke/VarHandles/X-VarHandleTestMethodHandleAccess.java.template @@ -30,6 +30,7 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; +import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -209,9 +210,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(recv, $value1$, $value2$); + success = (boolean) mh.invokeExact(recv, $value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -226,9 +229,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(recv, $value2$, $value1$); + success = (boolean) mh.invokeExact(recv, $value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -243,9 +248,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(recv, $value1$, $value2$); + success = (boolean) mh.invokeExact(recv, $value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -261,8 +268,10 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { { boolean success = false; + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(recv, $value2$, $value1$); + success = (boolean) mh.invokeExact(recv, $value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(recv); @@ -532,9 +541,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact($value1$, $value2$); + success = (boolean) mh.invokeExact($value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); @@ -549,9 +560,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact($value2$, $value1$); + success = (boolean) mh.invokeExact($value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); @@ -559,16 +572,19 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { - boolean success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact($value2$, $value3$); + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); + boolean success = (boolean) mh.invokeExact($value2$, $value3$); assertEquals(success, false, "failing weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); assertEquals(x, $value1$, "failing weakCompareAndSetAcquire $type$ value"); } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact($value1$, $value2$); + success = (boolean) mh.invokeExact($value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); @@ -583,9 +599,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact($value2$, $value1$); + success = (boolean) mh.invokeExact($value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(); @@ -880,9 +898,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_PLAIN).invokeExact(array, i, $value1$, $value2$); + success = (boolean) mh.invokeExact(array, i, $value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetPlain $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -897,9 +917,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_ACQUIRE).invokeExact(array, i, $value2$, $value1$); + success = (boolean) mh.invokeExact(array, i, $value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetAcquire $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -914,9 +936,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET_RELEASE).invokeExact(array, i, $value1$, $value2$); + success = (boolean) mh.invokeExact(array, i, $value1$, $value2$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSetRelease $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); @@ -931,9 +955,11 @@ public class VarHandleTestMethodHandleAccess$Type$ extends VarHandleBaseTest { } { + MethodHandle mh = hs.get(TestAccessMode.WEAK_COMPARE_AND_SET); boolean success = false; for (int c = 0; c < WEAK_ATTEMPTS && !success; c++) { - success = (boolean) hs.get(TestAccessMode.WEAK_COMPARE_AND_SET).invokeExact(array, i, $value2$, $value1$); + success = (boolean) mh.invokeExact(array, i, $value2$, $value1$); + if (!success) weakDelay(); } assertEquals(success, true, "success weakCompareAndSet $type$"); $type$ x = ($type$) hs.get(TestAccessMode.GET).invokeExact(array, i); From c118b0e9c835fdec7c0e5ac743d70d4cbda15ad5 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Mon, 13 Mar 2023 10:25:40 +0000 Subject: [PATCH 003/217] 8270859: Post JEP 411 refactoring: client libs with maximum covering > 10K Backport-of: 90cd2fa16458dcc3e36171fa4bf21f26bc92b168 --- .../classes/com/apple/eio/FileManager.java | 17 ++++++- .../classes/com/apple/laf/AquaFileView.java | 7 ++- .../classes/com/apple/laf/ScreenMenu.java | 7 ++- .../sun/lwawt/macosx/CAccessibility.java | 8 +++- .../classes/sun/lwawt/macosx/LWCToolkit.java | 21 ++++---- .../share/classes/java/awt/EventQueue.java | 22 +++++---- .../share/classes/javax/print/DocFlavor.java | 8 +--- .../share/classes/javax/swing/ImageIcon.java | 48 +++++++++---------- .../share/classes/javax/swing/JPopupMenu.java | 13 ++--- .../share/classes/javax/swing/JRootPane.java | 21 ++++---- .../swing/SortingFocusTraversalPolicy.java | 11 ++--- .../share/classes/sun/font/FontUtilities.java | 5 +- .../share/classes/sun/font/StrikeCache.java | 6 ++- .../sun/java2d/SunGraphicsEnvironment.java | 15 +++--- .../classes/sun/swing/JLightweightFrame.java | 35 +++++++------- .../sun/awt/X11GraphicsEnvironment.java | 8 +++- .../unix/classes/sun/print/CUPSPrinter.java | 8 +++- .../sun/print/PrintServiceLookupProvider.java | 17 ++++--- .../unix/classes/sun/print/UnixPrintJob.java | 7 +-- .../classes/sun/print/UnixPrintService.java | 8 ++-- .../classes/sun/awt/Win32FontManager.java | 19 ++++---- .../sun/print/PrintServiceLookupProvider.java | 10 +++- 22 files changed, 185 insertions(+), 136 deletions(-) diff --git a/src/java.desktop/macosx/classes/com/apple/eio/FileManager.java b/src/java.desktop/macosx/classes/com/apple/eio/FileManager.java index 2ccdf0eca15..8967a99f15e 100644 --- a/src/java.desktop/macosx/classes/com/apple/eio/FileManager.java +++ b/src/java.desktop/macosx/classes/com/apple/eio/FileManager.java @@ -53,9 +53,13 @@ * * @since 1.4 */ -@SuppressWarnings("removal") public class FileManager { static { + loadOSXLibrary(); + } + + @SuppressWarnings("removal") + private static void loadOSXLibrary() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { @@ -132,6 +136,7 @@ public static int OSTypeToInt(String type) { * @since 1.4 */ public static void setFileTypeAndCreator(String filename, int type, int creator) throws IOException { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(filename); @@ -146,6 +151,7 @@ public static void setFileTypeAndCreator(String filename, int type, int creator) * @since 1.4 */ public static void setFileType(String filename, int type) throws IOException { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(filename); @@ -160,6 +166,7 @@ public static void setFileType(String filename, int type) throws IOException { * @since 1.4 */ public static void setFileCreator(String filename, int creator) throws IOException { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkWrite(filename); @@ -174,6 +181,7 @@ public static void setFileCreator(String filename, int creator) throws IOExcepti * @since 1.4 */ public static int getFileType(String filename) throws IOException { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(filename); @@ -188,6 +196,7 @@ public static int getFileType(String filename) throws IOException { * @since 1.4 */ public static int getFileCreator(String filename) throws IOException { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(filename); @@ -251,6 +260,7 @@ public static String findFolder(short domain, int folderType) throws FileNotFoun * @since 1.4 */ public static String findFolder(short domain, int folderType, boolean createIfNeeded) throws FileNotFoundException { + @SuppressWarnings("removal") final SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(new RuntimePermission("canExamineFileSystem")); @@ -278,6 +288,7 @@ public static String findFolder(short domain, int folderType, boolean createIfNe */ @Deprecated public static void openURL(String url) throws IOException { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(new RuntimePermission("canOpenURLs")); @@ -329,6 +340,7 @@ public static String getResource(String resourceName, String subDirName, String private static native String getNativeResourceFromBundle(String resourceName, String subDirName, String type) throws FileNotFoundException; private static String getResourceFromBundle(String resourceName, String subDirName, String type) throws FileNotFoundException { + @SuppressWarnings("removal") final SecurityManager security = System.getSecurityManager(); if (security != null) security.checkPermission(new RuntimePermission("canReadBundle")); @@ -347,6 +359,7 @@ private static String getResourceFromBundle(String resourceName, String subDirNa * @since Java for Mac OS X 10.5 Update 2 - 1.5 */ public static String getPathToApplicationBundle() { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) security.checkPermission(new RuntimePermission("canReadBundle")); return getNativePathToApplicationBundle(); @@ -368,6 +381,7 @@ public static boolean moveToTrash(final File file) throws FileNotFoundException if (file == null) throw new FileNotFoundException(); final String fileName = file.getAbsolutePath(); + @SuppressWarnings("removal") final SecurityManager security = System.getSecurityManager(); if (security != null) security.checkDelete(fileName); @@ -391,6 +405,7 @@ public static boolean revealInFinder(final File file) throws FileNotFoundExcepti if (file == null || !file.exists()) throw new FileNotFoundException(); final String fileName = file.getAbsolutePath(); + @SuppressWarnings("removal") final SecurityManager security = System.getSecurityManager(); if (security != null) security.checkRead(fileName); diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileView.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileView.java index e4e9a383153..d9f9a66e44c 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileView.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileView.java @@ -34,7 +34,7 @@ import com.apple.laf.AquaUtils.RecyclableSingleton; -@SuppressWarnings({"removal","serial"}) // JDK implementation class +@SuppressWarnings("serial") // JDK implementation class class AquaFileView extends FileView { private static final boolean DEBUG = false; @@ -57,6 +57,11 @@ class AquaFileView extends FileView { static final int kLSItemInfoExtensionIsHidden = 0x00100000; /* Item has a hidden extension*/ static { + loadOSXUILibrary(); + } + + @SuppressWarnings("removal") + private static void loadOSXUILibrary() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { diff --git a/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java b/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java index 66748944d31..4f6e006faf8 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java @@ -36,12 +36,17 @@ import sun.lwawt.LWToolkit; import sun.lwawt.macosx.*; -@SuppressWarnings({"removal","serial"}) // JDK implementation class +@SuppressWarnings("serial") // JDK implementation class final class ScreenMenu extends Menu implements ContainerListener, ComponentListener, ScreenMenuPropertyHandler { static { + loadAWTLibrary(); + } + + @SuppressWarnings("removal") + private static void loadAWTLibrary() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java index 4f4578caecd..2f23d8d0fdf 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java @@ -67,12 +67,16 @@ import sun.awt.AWTAccessor; import sun.lwawt.LWWindowPeer; -@SuppressWarnings("removal") class CAccessibility implements PropertyChangeListener { private static Set ignoredRoles; static { - // Need to load the native library for this code. + loadAWTLibrary(); + } + + @SuppressWarnings("removal") + private static void loadAWTLibrary() { + // Need to load the native library for this code. java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index b742ac9e38d..1b037510299 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -131,7 +131,6 @@ final class NamedCursor extends Cursor { /** * Mac OS X Cocoa-based AWT Toolkit. */ -@SuppressWarnings("removal") public final class LWCToolkit extends LWToolkit { // While it is possible to enumerate all mouse devices // and query them for the number of buttons, the code @@ -147,6 +146,7 @@ public final class LWCToolkit extends LWToolkit { static { System.err.flush(); + @SuppressWarnings("removal") ResourceBundle platformResources = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { @Override @@ -176,20 +176,23 @@ public ResourceBundle run() { if (!GraphicsEnvironment.isHeadless()) { initIDs(); } - inAWT = AccessController.doPrivileged(new PrivilegedAction() { - @Override - public Boolean run() { - return !Boolean.parseBoolean(System.getProperty("javafx.embed.singleThread", "false")); - } - }); } /* * If true we operate in normal mode and nested runloop is executed in JavaRunLoopMode * If false we operate in singleThreaded FX/AWT interop mode and nested loop uses NSDefaultRunLoopMode */ - private static final boolean inAWT; + @SuppressWarnings("removal") + private static final boolean inAWT + = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Boolean run() { + return !Boolean.parseBoolean( + System.getProperty("javafx.embed.singleThread", "false")); + } + }); + @SuppressWarnings("removal") public LWCToolkit() { final String extraButtons = "sun.awt.enableExtraMouseButtons"; AccessController.doPrivileged((PrivilegedAction) () -> { @@ -248,6 +251,7 @@ public static Color getAppleColor(int color) { } // This is only called from native code. + @SuppressWarnings("removal") static void systemColorsChanged() { EventQueue.invokeLater(() -> { AccessController.doPrivileged( (PrivilegedAction) () -> { @@ -586,6 +590,7 @@ public boolean isAlwaysOnTopSupported() { private static final String APPKIT_THREAD_NAME = "AppKit Thread"; // Intended to be called from the LWCToolkit.m only. + @SuppressWarnings("removal") private static void installToolkitThreadInJava() { Thread.currentThread().setName(APPKIT_THREAD_NAME); AccessController.doPrivileged((PrivilegedAction) () -> { diff --git a/src/java.desktop/share/classes/java/awt/EventQueue.java b/src/java.desktop/share/classes/java/awt/EventQueue.java index eec41c454e1..e7d1dcc8286 100644 --- a/src/java.desktop/share/classes/java/awt/EventQueue.java +++ b/src/java.desktop/share/classes/java/awt/EventQueue.java @@ -94,7 +94,6 @@ * * @since 1.1 */ -@SuppressWarnings("removal") public class EventQueue { private static final AtomicInteger threadInitNumber = new AtomicInteger(); @@ -192,8 +191,6 @@ private static final PlatformLogger getEventLog() { return eventLog; } - private static boolean fxAppThreadIsDispatchThread; - static { AWTAccessor.setEventQueueAccessor( new AWTAccessor.EventQueueAccessor() { @@ -230,15 +227,16 @@ public long getMostRecentEventTime(EventQueue eventQueue) { return eventQueue.getMostRecentEventTimeImpl(); } }); - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - fxAppThreadIsDispatchThread = - "true".equals(System.getProperty("javafx.embed.singleThread")); - return null; - } - }); } + @SuppressWarnings("removal") + private static boolean fxAppThreadIsDispatchThread = + AccessController.doPrivileged(new PrivilegedAction() { + public Boolean run() { + return "true".equals(System.getProperty("javafx.embed.singleThread")); + } + }); + /** * Initializes a new instance of {@code EventQueue}. */ @@ -734,8 +732,11 @@ public void run() { } }; + @SuppressWarnings("removal") final AccessControlContext stack = AccessController.getContext(); + @SuppressWarnings("removal") final AccessControlContext srcAcc = getAccessControlContextFrom(src); + @SuppressWarnings("removal") final AccessControlContext eventAcc = event.getAccessControlContext(); if (srcAcc == null) { javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc); @@ -750,6 +751,7 @@ public Void run() { } } + @SuppressWarnings("removal") private static AccessControlContext getAccessControlContextFrom(Object src) { return src instanceof Component ? ((Component)src).getAccessControlContext() : diff --git a/src/java.desktop/share/classes/javax/print/DocFlavor.java b/src/java.desktop/share/classes/javax/print/DocFlavor.java index 746c5ed0fa6..557a1799a24 100644 --- a/src/java.desktop/share/classes/javax/print/DocFlavor.java +++ b/src/java.desktop/share/classes/javax/print/DocFlavor.java @@ -385,7 +385,6 @@ * * @author Alan Kaminsky */ -@SuppressWarnings("removal") public class DocFlavor implements Serializable, Cloneable { /** @@ -405,13 +404,10 @@ public class DocFlavor implements Serializable, Cloneable { * This is the charset for all the "HOST" pre-defined {@code DocFlavors} in * the executing VM. */ - public static final String hostEncoding; - - static { - hostEncoding = + @SuppressWarnings("removal") + public static final String hostEncoding = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("file.encoding")); - } /** * MIME type. diff --git a/src/java.desktop/share/classes/javax/swing/ImageIcon.java b/src/java.desktop/share/classes/javax/swing/ImageIcon.java index 1ddca794779..566e1c8f870 100644 --- a/src/java.desktop/share/classes/javax/swing/ImageIcon.java +++ b/src/java.desktop/share/classes/javax/swing/ImageIcon.java @@ -85,7 +85,7 @@ * @author Lynn Monsanto * @since 1.2 */ -@SuppressWarnings({"removal","serial"}) // Same-version serialization only +@SuppressWarnings("serial") // Same-version serialization only public class ImageIcon implements Icon, Serializable, Accessible { /* Keep references to the filename and location so that * alternate persistence schemes have the option to archive @@ -105,8 +105,27 @@ public class ImageIcon implements Icon, Serializable, Accessible { * It is left for backward compatibility only. * @deprecated since 1.8 */ + @SuppressWarnings("removal") @Deprecated - protected static final Component component; + protected static final Component component + = AccessController.doPrivileged(new PrivilegedAction() { + public Component run() { + try { + final Component component = createNoPermsComponent(); + + // 6482575 - clear the appContext field so as not to leak it + AWTAccessor.getComponentAccessor(). + setAppContext(component, null); + + return component; + } catch (Throwable e) { + // We don't care about component. + // So don't prevent class initialisation. + e.printStackTrace(); + return null; + } + } + }); /** * Do not use this shared media tracker, which is used to load images. @@ -114,30 +133,9 @@ public class ImageIcon implements Icon, Serializable, Accessible { * @deprecated since 1.8 */ @Deprecated - protected static final MediaTracker tracker; - - static { - component = AccessController.doPrivileged(new PrivilegedAction() { - public Component run() { - try { - final Component component = createNoPermsComponent(); - - // 6482575 - clear the appContext field so as not to leak it - AWTAccessor.getComponentAccessor(). - setAppContext(component, null); - - return component; - } catch (Throwable e) { - // We don't care about component. - // So don't prevent class initialisation. - e.printStackTrace(); - return null; - } - } - }); - tracker = new MediaTracker(component); - } + protected static final MediaTracker tracker = new MediaTracker(component); + @SuppressWarnings("removal") private static Component createNoPermsComponent() { // 7020198 - set acc field to no permissions and no subject // Note, will have appContext set. diff --git a/src/java.desktop/share/classes/javax/swing/JPopupMenu.java b/src/java.desktop/share/classes/javax/swing/JPopupMenu.java index 639c640862d..e4eb45c28a9 100644 --- a/src/java.desktop/share/classes/javax/swing/JPopupMenu.java +++ b/src/java.desktop/share/classes/javax/swing/JPopupMenu.java @@ -101,7 +101,7 @@ */ @JavaBean(defaultProperty = "UI", description = "A small window that pops up and displays a series of choices.") @SwingContainer(false) -@SuppressWarnings({"removal","serial"}) +@SuppressWarnings("serial") public class JPopupMenu extends JComponent implements Accessible,MenuElement { /** @@ -117,14 +117,11 @@ public class JPopupMenu extends JComponent implements Accessible,MenuElement { new StringBuffer("JPopupMenu.defaultLWPopupEnabledKey"); /** Bug#4425878-Property javax.swing.adjustPopupLocationToFit introduced */ - static boolean popupPostionFixDisabled = false; - - static { - popupPostionFixDisabled = java.security.AccessController.doPrivileged( + @SuppressWarnings("removal") + static boolean popupPostionFixDisabled = + java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction( - "javax.swing.adjustPopupLocationToFit","")).equals("false"); - - } + "javax.swing.adjustPopupLocationToFit","")).equals("false"); transient Component invoker; transient Popup popup; diff --git a/src/java.desktop/share/classes/javax/swing/JRootPane.java b/src/java.desktop/share/classes/javax/swing/JRootPane.java index 0a2e0c3a89a..e3eb7ac75a4 100644 --- a/src/java.desktop/share/classes/javax/swing/JRootPane.java +++ b/src/java.desktop/share/classes/javax/swing/JRootPane.java @@ -199,7 +199,7 @@ * @since 1.2 */ /// PENDING(klobad) Who should be opaque in this component? -@SuppressWarnings({"removal","serial"}) +@SuppressWarnings("serial") public class JRootPane extends JComponent implements Accessible { private static final String uiClassID = "RootPaneUI"; @@ -208,13 +208,19 @@ public class JRootPane extends JComponent implements Accessible { * Whether or not we should dump the stack when true double buffering * is disabled. Default is false. */ - private static final boolean LOG_DISABLE_TRUE_DOUBLE_BUFFERING; + @SuppressWarnings("removal") + private static final boolean LOG_DISABLE_TRUE_DOUBLE_BUFFERING + = AccessController.doPrivileged(new GetBooleanAction( + "swing.logDoubleBufferingDisable")); /** * Whether or not we should ignore requests to disable true double * buffering. Default is false. */ - private static final boolean IGNORE_DISABLE_TRUE_DOUBLE_BUFFERING; + @SuppressWarnings("removal") + private static final boolean IGNORE_DISABLE_TRUE_DOUBLE_BUFFERING + = AccessController.doPrivileged(new GetBooleanAction( + "swing.ignoreDoubleBufferingDisable")); /** * Constant used for the windowDecorationStyle property. Indicates that @@ -326,15 +332,6 @@ public class JRootPane extends JComponent implements Accessible { */ boolean useTrueDoubleBuffering = true; - static { - LOG_DISABLE_TRUE_DOUBLE_BUFFERING = - AccessController.doPrivileged(new GetBooleanAction( - "swing.logDoubleBufferingDisable")); - IGNORE_DISABLE_TRUE_DOUBLE_BUFFERING = - AccessController.doPrivileged(new GetBooleanAction( - "swing.ignoreDoubleBufferingDisable")); - } - /** * Creates a JRootPane, setting up its * glassPane, layeredPane, diff --git a/src/java.desktop/share/classes/javax/swing/SortingFocusTraversalPolicy.java b/src/java.desktop/share/classes/javax/swing/SortingFocusTraversalPolicy.java index 4eb8fef4200..5305be37e86 100644 --- a/src/java.desktop/share/classes/javax/swing/SortingFocusTraversalPolicy.java +++ b/src/java.desktop/share/classes/javax/swing/SortingFocusTraversalPolicy.java @@ -59,7 +59,6 @@ * @see java.util.Comparator * @since 1.4 */ -@SuppressWarnings("removal") public class SortingFocusTraversalPolicy extends InternalFrameFocusTraversalPolicy { @@ -96,12 +95,10 @@ public class SortingFocusTraversalPolicy * When false, the default (tim-sort) algo is used, which may lead to an exception. * See: JDK-8048887 */ - private static final boolean legacySortingFTPEnabled; - - static { - legacySortingFTPEnabled = "true".equals(AccessController.doPrivileged( - new GetPropertyAction("swing.legacySortingFTPEnabled", "true"))); - } + @SuppressWarnings("removal") + private static final boolean legacySortingFTPEnabled = "true".equals( + AccessController.doPrivileged( + new GetPropertyAction("swing.legacySortingFTPEnabled", "true"))); /** * Constructs a SortingFocusTraversalPolicy without a Comparator. diff --git a/src/java.desktop/share/classes/sun/font/FontUtilities.java b/src/java.desktop/share/classes/sun/font/FontUtilities.java index 79ea7de393c..550cdcce3cf 100644 --- a/src/java.desktop/share/classes/sun/font/FontUtilities.java +++ b/src/java.desktop/share/classes/sun/font/FontUtilities.java @@ -38,7 +38,6 @@ /** * A collection of utility methods. */ -@SuppressWarnings("removal") public final class FontUtilities { public static boolean isLinux; @@ -56,7 +55,11 @@ public final class FontUtilities { // This static initializer block figures out the OS constants. static { + initStatic(); + } + @SuppressWarnings("removal") + private static void initStatic() { AccessController.doPrivileged(new PrivilegedAction() { @SuppressWarnings("deprecation") // PlatformLogger.setLevel is deprecated. @Override diff --git a/src/java.desktop/share/classes/sun/font/StrikeCache.java b/src/java.desktop/share/classes/sun/font/StrikeCache.java index c550b63562b..866498df6ee 100644 --- a/src/java.desktop/share/classes/sun/font/StrikeCache.java +++ b/src/java.desktop/share/classes/sun/font/StrikeCache.java @@ -61,7 +61,6 @@ */ -@SuppressWarnings("removal") public final class StrikeCache { static final Unsafe unsafe = Unsafe.getUnsafe(); @@ -135,6 +134,11 @@ public final class StrikeCache { static native void getGlyphCacheDescription(long[] infoArray); static { + initStatic(); + } + + @SuppressWarnings("removal") + private static void initStatic() { long[] nativeInfo = new long[13]; getGlyphCacheDescription(nativeInfo); diff --git a/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java b/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java index 014281e0811..e7ef49b1fc9 100644 --- a/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java +++ b/src/java.desktop/share/classes/sun/java2d/SunGraphicsEnvironment.java @@ -59,21 +59,19 @@ * @see GraphicsDevice * @see GraphicsConfiguration */ -@SuppressWarnings("removal") public abstract class SunGraphicsEnvironment extends GraphicsEnvironment implements DisplayChangedListener { /** Establish the default font to be used by SG2D. */ private final Font defaultFont = new Font(Font.DIALOG, Font.PLAIN, 12); - private static final boolean uiScaleEnabled; - private static final double debugScale; + @SuppressWarnings("removal") + private static final boolean uiScaleEnabled + = "true".equals(AccessController.doPrivileged( + new GetPropertyAction("sun.java2d.uiScale.enabled", "true"))); - static { - uiScaleEnabled = "true".equals(AccessController.doPrivileged( - new GetPropertyAction("sun.java2d.uiScale.enabled", "true"))); - debugScale = uiScaleEnabled ? getScaleFactor("sun.java2d.uiScale") : -1; - } + private static final double debugScale = + uiScaleEnabled ? getScaleFactor("sun.java2d.uiScale") : -1; protected GraphicsDevice[] screens; @@ -299,6 +297,7 @@ public static double getDebugScale() { public static double getScaleFactor(String propertyName) { + @SuppressWarnings("removal") String scaleFactor = AccessController.doPrivileged( new GetPropertyAction(propertyName, "-1")); diff --git a/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java b/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java index 609ec8c7aa9..c1167b4d8ba 100644 --- a/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java +++ b/src/java.desktop/share/classes/sun/swing/JLightweightFrame.java @@ -68,7 +68,7 @@ * @author Artem Ananiev * @author Anton Tarasov */ -@SuppressWarnings({"removal","serial"}) // JDK-implementation class +@SuppressWarnings("serial") // JDK-implementation class public final class JLightweightFrame extends LightweightFrame implements RootPaneContainer { private final JRootPane rootPane = new JRootPane(); @@ -83,19 +83,6 @@ public final class JLightweightFrame extends LightweightFrame implements RootPan private volatile double scaleFactorX; private volatile double scaleFactorY; - /** - * {@code copyBufferEnabled}, true by default, defines the following strategy. - * A duplicating (copy) buffer is created for the original pixel buffer. - * The copy buffer is synchronized with the original buffer every time the - * latter changes. {@code JLightweightFrame} passes the copy buffer array - * to the {@link LightweightContent#imageBufferReset} method. The code spot - * which synchronizes two buffers becomes the only critical section guarded - * by the lock (managed with the {@link LightweightContent#paintLock()}, - * {@link LightweightContent#paintUnlock()} methods). - */ - private static boolean copyBufferEnabled; - private int[] copyBuffer; - private PropertyChangeListener layoutSizeListener; private RepaintListener repaintListener; @@ -106,14 +93,28 @@ public void updateCursor(JLightweightFrame frame) { frame.updateClientCursor(); } }); - copyBufferEnabled = "true".equals(AccessController. - doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true"))); } + /** + * {@code copyBufferEnabled}, true by default, defines the following strategy. + * A duplicating (copy) buffer is created for the original pixel buffer. + * The copy buffer is synchronized with the original buffer every time the + * latter changes. {@code JLightweightFrame} passes the copy buffer array + * to the {@link LightweightContent#imageBufferReset} method. The code spot + * which synchronizes two buffers becomes the only critical section guarded + * by the lock (managed with the {@link LightweightContent#paintLock()}, + * {@link LightweightContent#paintUnlock()} methods). + */ + @SuppressWarnings("removal") + private static boolean copyBufferEnabled = "true".equals(AccessController. + doPrivileged(new GetPropertyAction("swing.jlf.copyBufferEnabled", "true"))); + private int[] copyBuffer; + /** * Constructs a new, initially invisible {@code JLightweightFrame} * instance. */ + @SuppressWarnings("removal") public JLightweightFrame() { super(); AffineTransform defaultTransform = @@ -330,7 +331,7 @@ private void notifyImageUpdated(int x, int y, int width, int height) { content.imageUpdated(x, y, width, height); } - @SuppressWarnings("serial") // anonymous class inside + @SuppressWarnings({"removal","serial"}) // anonymous class inside private void initInterior() { contentPane = new JPanel() { @Override diff --git a/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java b/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java index 40962e43c1f..8206d18906f 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java +++ b/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java @@ -53,10 +53,14 @@ * @see GraphicsDevice * @see java.awt.GraphicsConfiguration */ -@SuppressWarnings("removal") public final class X11GraphicsEnvironment extends SunGraphicsEnvironment { static { + initStatic(); + } + + @SuppressWarnings("removal") + private static void initStatic() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Object run() { @@ -295,6 +299,7 @@ private static boolean _isDisplayLocal() { return true; } + @SuppressWarnings("removal") String isRemote = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("sun.java2d.remote")); if (isRemote != null) { @@ -317,6 +322,7 @@ private static boolean _isDisplayLocal() { return true; } + @SuppressWarnings("removal") Boolean result = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Boolean run() { diff --git a/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java b/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java index b7715a87860..0e398edef85 100644 --- a/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java +++ b/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java @@ -46,7 +46,6 @@ import javax.print.attribute.standard.PrinterName; -@SuppressWarnings("removal") public class CUPSPrinter { private static final String debugPrefix = "CUPSPrinter>> "; private static final double PRINTER_DPI = 72.0; @@ -83,6 +82,11 @@ public class CUPSPrinter { private static int cupsPort = 0; static { + initStatic(); + } + + @SuppressWarnings("removal") + private static void initStatic() { // load awt library to access native code java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { @@ -292,6 +296,7 @@ static String[] getDefaultPrinter() { IPPPrintService.getIPPConnection(url); if (urlConnection != null) { + @SuppressWarnings("removal") OutputStream os = java.security.AccessController. doPrivileged(new java.security.PrivilegedAction() { public OutputStream run() { @@ -406,6 +411,7 @@ static String[] getAllPrinters() { IPPPrintService.getIPPConnection(url); if (urlConnection != null) { + @SuppressWarnings("removal") OutputStream os = java.security.AccessController. doPrivileged(new java.security.PrivilegedAction() { public OutputStream run() { diff --git a/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java b/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java index 79fc2fd15ee..eeff669dfce 100644 --- a/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java +++ b/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java @@ -58,7 +58,6 @@ * Remind: This class uses solaris commands. We also need a linux * version */ -@SuppressWarnings("removal") public class PrintServiceLookupProvider extends PrintServiceLookup implements BackgroundServiceLookup, Runnable { @@ -76,8 +75,9 @@ public class PrintServiceLookupProvider extends PrintServiceLookup private static final int DEFAULT_MINREFRESH = 120; // 2 minutes private static int minRefreshTime = DEFAULT_MINREFRESH; - - static String osname; + @SuppressWarnings("removal") + static String osname = java.security.AccessController.doPrivileged( + new sun.security.action.GetPropertyAction("os.name")); // List of commands used to deal with the printer queues on AIX String[] lpNameComAix = { @@ -97,6 +97,7 @@ public class PrintServiceLookupProvider extends PrintServiceLookup * can be used to force the printing code to poll or not poll * for PrintServices. */ + @SuppressWarnings("removal") String pollStr = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("sun.java2d.print.polling")); @@ -112,6 +113,7 @@ public class PrintServiceLookupProvider extends PrintServiceLookup * can be used to specify minimum refresh time (in seconds) * for polling PrintServices. The default is 120. */ + @SuppressWarnings("removal") String refreshTimeStr = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction( "sun.java2d.print.minRefreshTime")); @@ -126,15 +128,13 @@ public class PrintServiceLookupProvider extends PrintServiceLookup } } - osname = java.security.AccessController.doPrivileged( - new sun.security.action.GetPropertyAction("os.name")); - /* The system property "sun.java2d.print.aix.lpstat" * can be used to force the usage of 'lpstat -p' to enumerate all * printer queues. By default we use 'lsallq', because 'lpstat -p' can * take lots of time if thousands of printers are attached to a server. */ if (isAIX()) { + @SuppressWarnings("removal") String aixPrinterEnumerator = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("sun.java2d.print.aix.lpstat")); @@ -222,6 +222,7 @@ public PrintServiceLookupProvider() { * lead people to assume its guaranteed. */ public synchronized PrintService[] getPrintServices() { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); @@ -560,6 +561,7 @@ private PrintService getServiceByName(PrinterName nameAttr) { */ public PrintService[] getPrintServices(DocFlavor flavor, AttributeSet attributes) { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); @@ -623,6 +625,7 @@ public PrintService[] getPrintServices(DocFlavor flavor, public MultiDocPrintService[] getMultiDocPrintServices(DocFlavor[] flavors, AttributeSet attributes) { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); @@ -632,6 +635,7 @@ public PrintService[] getPrintServices(DocFlavor flavor, public synchronized PrintService getDefaultPrintService() { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); @@ -865,6 +869,7 @@ private String[] getAllPrinterNamesAIX() { return printerNames.toArray(new String[printerNames.size()]); } + @SuppressWarnings("removal") static String[] execCmd(final String command) { ArrayList results = null; try { diff --git a/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java b/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java index 4f810d947d4..89e76d20c57 100644 --- a/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java +++ b/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java @@ -309,7 +309,6 @@ public void removePrintJobAttributeListener( } } - @SuppressWarnings("removal") public void print(Doc doc, PrintRequestAttributeSet attributes) throws PrintException { @@ -536,7 +535,8 @@ public void print(Doc doc, PrintRequestAttributeSet attributes) // now spool the print data. PrinterOpener po = new PrinterOpener(); - java.security.AccessController.doPrivileged(po); + @SuppressWarnings("removal") + var dummy = java.security.AccessController.doPrivileged(po); if (po.pex != null) { throw po.pex; } @@ -609,7 +609,8 @@ public void print(Doc doc, PrintRequestAttributeSet attributes) if (mDestType == UnixPrintJob.DESTPRINTER) { PrinterSpooler spooler = new PrinterSpooler(); - java.security.AccessController.doPrivileged(spooler); + @SuppressWarnings("removal") + var dummy2 = java.security.AccessController.doPrivileged(spooler); if (spooler.pex != null) { throw spooler.pex; } diff --git a/src/java.desktop/unix/classes/sun/print/UnixPrintService.java b/src/java.desktop/unix/classes/sun/print/UnixPrintService.java index 2a11a6e2d05..bbd8c6c9c78 100644 --- a/src/java.desktop/unix/classes/sun/print/UnixPrintService.java +++ b/src/java.desktop/unix/classes/sun/print/UnixPrintService.java @@ -74,14 +74,12 @@ import javax.print.event.PrintServiceAttributeListener; -@SuppressWarnings("removal") public class UnixPrintService implements PrintService, AttributeUpdater, SunPrinterJobService { /* define doc flavors for text types in the default encoding of * this platform since we can always read those. */ - private static String encoding = "ISO8859_1"; private static DocFlavor textByteFlavor; private static DocFlavor[] supportedDocFlavors = null; @@ -147,10 +145,9 @@ public class UnixPrintService implements PrintService, AttributeUpdater, "| grep -E '^[ 0-9a-zA-Z_-]*@' | awk '{print $4}'" }; - static { - encoding = java.security.AccessController.doPrivileged( + @SuppressWarnings("removal") + private static String encoding = java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("file.encoding")); - } /* let's try to support a few of these */ private static final Class[] serviceAttrCats = { @@ -421,6 +418,7 @@ private boolean isSupportedMedia(MediaSizeName msn) { } public DocPrintJob createPrintJob() { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); diff --git a/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java b/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java index 8b6c5b96903..6ea0b16bcdb 100644 --- a/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java +++ b/src/java.desktop/windows/classes/sun/awt/Win32FontManager.java @@ -45,32 +45,26 @@ /** * The X11 implementation of {@link FontManager}. */ -@SuppressWarnings("removal") public final class Win32FontManager extends SunFontManager { - private static TrueTypeFont eudcFont; - - static { - - AccessController.doPrivileged(new PrivilegedAction() { - - public Object run() { + @SuppressWarnings("removal") + private static final TrueTypeFont eudcFont = + AccessController.doPrivileged(new PrivilegedAction() { + public TrueTypeFont run() { String eudcFile = getEUDCFontFile(); if (eudcFile != null) { try { /* Must use Java rasteriser since GDI doesn't * enumerate (allow direct use) of EUDC fonts. */ - eudcFont = new TrueTypeFont(eudcFile, null, 0, + return new TrueTypeFont(eudcFile, null, 0, true, false); } catch (FontFormatException e) { } } return null; } - }); - } /* Used on Windows to obtain from the windows registry the name * of a file containing the system EUFC font. If running in one of @@ -84,6 +78,7 @@ public TrueTypeFont getEUDCFont() { return eudcFont; } + @SuppressWarnings("removal") public Win32FontManager() { super(); AccessController.doPrivileged(new PrivilegedAction() { @@ -218,6 +213,7 @@ protected String[] getDefaultPlatformFont() { info[1] = "c:\\windows\\fonts"; final String[] dirs = getPlatformFontDirs(true); if (dirs.length > 1) { + @SuppressWarnings("removal") String dir = (String) AccessController.doPrivileged(new PrivilegedAction() { public Object run() { @@ -252,6 +248,7 @@ protected void registerJREFontsWithPlatform(String pathName) { fontsForPrinting = pathName; } + @SuppressWarnings("removal") public static void registerJREFontsForPrinting() { final String pathName; synchronized (Win32GraphicsEnvironment.class) { diff --git a/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java b/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java index 8233e7454f9..1d76ebae479 100644 --- a/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java +++ b/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java @@ -41,13 +41,17 @@ import javax.print.attribute.PrintServiceAttributeSet; import javax.print.attribute.standard.PrinterName; -@SuppressWarnings("removal") public class PrintServiceLookupProvider extends PrintServiceLookup { private PrintService defaultPrintService; private PrintService[] printServices; /* includes the default printer */ static { + loadAWTLibrary(); + } + + @SuppressWarnings("removal") + private static void loadAWTLibrary() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Void run() { @@ -102,6 +106,7 @@ public PrintServiceLookupProvider() { * lead people to assume its guaranteed. */ public synchronized PrintService[] getPrintServices() { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); @@ -202,6 +207,7 @@ boolean matchingService(PrintService service, public PrintService[] getPrintServices(DocFlavor flavor, AttributeSet attributes) { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); @@ -267,6 +273,7 @@ public PrintService[] getPrintServices(DocFlavor flavor, public MultiDocPrintService[] getMultiDocPrintServices(DocFlavor[] flavors, AttributeSet attributes) { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); @@ -276,6 +283,7 @@ public PrintService[] getPrintServices(DocFlavor flavor, public synchronized PrintService getDefaultPrintService() { + @SuppressWarnings("removal") SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPrintJobAccess(); From b087032f9b26b9756da9f5dc368b1b564c9c5048 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Mon, 13 Mar 2023 18:55:26 +0000 Subject: [PATCH 004/217] 8303440: The "ZonedDateTime.parse" may not accept the "UTC+XX" zone id Backport-of: cfb0a25a4ee1a9cebd88c84fa622c46fe1c89bae --- .../time/format/DateTimeFormatterBuilder.java | 6 +- .../test/java/time/format/TestUTCParse.java | 77 +++++++++++++++++++ 2 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 test/jdk/java/time/test/java/time/format/TestUTCParse.java diff --git a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java index 3a0d7595616..50db24a61a1 100644 --- a/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java +++ b/src/java.base/share/classes/java/time/format/DateTimeFormatterBuilder.java @@ -4321,8 +4321,10 @@ public int parse(DateTimeParseContext context, CharSequence text, int position) if (length >= position + 3 && context.charEquals(text.charAt(position + 2), 'C')) { // There are localized zone texts that start with "UTC", e.g. // "UTC\u221210:00" (MINUS SIGN instead of HYPHEN-MINUS) in French. - // Exclude those ZoneText cases. - if (!(this instanceof ZoneTextPrinterParser)) { + // Exclude those cases. + if (length == position + 3 || + context.charEquals(text.charAt(position + 3), '+') || + context.charEquals(text.charAt(position + 3), '-')) { return parseOffsetBased(context, text, position, position + 3, OffsetIdPrinterParser.INSTANCE_ID_ZERO); } } else { diff --git a/test/jdk/java/time/test/java/time/format/TestUTCParse.java b/test/jdk/java/time/test/java/time/format/TestUTCParse.java new file mode 100644 index 00000000000..3f991810f8b --- /dev/null +++ b/test/jdk/java/time/test/java/time/format/TestUTCParse.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 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 + * 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. + */ +/* + * @test + * @modules jdk.localedata + * @bug 8303440 + * @summary Test parsing "UTC-XX:XX" text works correctly + */ +package test.java.time.format; + +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.DateTimeFormatterBuilder; +import java.time.format.TextStyle; +import java.time.temporal.TemporalQueries; +import java.util.Locale; + +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import static org.testng.Assert.assertEquals; + +public class TestUTCParse { + + static { + // Assuming CLDR's SHORT name for "America/Los_Angeles" + // produces "UTC\u212208:00" + System.setProperty("java.locale.providers", "CLDR"); + } + + @DataProvider + public Object[][] utcZoneIdStrings() { + return new Object[][] { + {"UTC"}, + {"UTC+01:30"}, + {"UTC-01:30"}, + }; + } + + @Test + public void testUTCShortNameRoundTrip() { + var fmt = DateTimeFormatter.ofPattern("z", Locale.FRANCE); + var zdt = ZonedDateTime.of(2023, 3, 3, 0, 0, 0, 0, ZoneId.of("America/Los_Angeles")); + var formatted = fmt.format(zdt); + assertEquals(formatted, "UTC\u221208:00"); + assertEquals(fmt.parse(formatted).query(TemporalQueries.zoneId()), zdt.getZone()); + } + + @Test(dataProvider = "utcZoneIdStrings") + public void testUTCOffsetRoundTrip(String zidString) { + var fmt = new DateTimeFormatterBuilder() + .appendZoneText(TextStyle.NARROW) + .toFormatter(); + var zid = ZoneId.of(zidString); + assertEquals(fmt.parse(zidString).query(TemporalQueries.zoneId()), zid); + } +} From bc79161e25c256d41650325f5e26e426c703ae6c Mon Sep 17 00:00:00 2001 From: Man Cao Date: Wed, 15 Mar 2023 07:16:31 +0000 Subject: [PATCH 005/217] 8303937: Corrupted heap dumps due to missing retries for os::write() Reviewed-by: clanger Backport-of: bf16b5b9880eb89b283006db090dce4346aa877b --- src/hotspot/share/services/heapDumperCompression.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/services/heapDumperCompression.cpp b/src/hotspot/share/services/heapDumperCompression.cpp index 41c97261094..222c6e383f2 100644 --- a/src/hotspot/share/services/heapDumperCompression.cpp +++ b/src/hotspot/share/services/heapDumperCompression.cpp @@ -54,10 +54,14 @@ char const* FileWriter::write_buf(char* buf, ssize_t size) { assert(_fd >= 0, "Must be open"); assert(size > 0, "Must write at least one byte"); - ssize_t n = (ssize_t) os::write(_fd, buf, (uint) size); + while (size > 0) { + ssize_t n = os::write(_fd, buf, (uint) size); + if (n <= 0) { + return os::strerror(errno); + } - if (n <= 0) { - return os::strerror(errno); + buf += n; + size -= n; } return NULL; From 4baaa110d6135adfb8e4c7ca9a0bef60ea93598c Mon Sep 17 00:00:00 2001 From: Johannes Bechberger Date: Wed, 15 Mar 2023 10:30:56 +0000 Subject: [PATCH 006/217] 8302320: AsyncGetCallTrace obtains too few frames in sanity test Backport-of: db483a38a815f85bd9668749674b5f0f6e4b27b4 --- src/hotspot/cpu/x86/frame_x86.cpp | 7 ++-- .../libAsyncGetCallTraceTest.cpp | 35 ++++++++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index 3faf6f99db8..aa5628a7f7e 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.cpp @@ -64,8 +64,11 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - // unextended sp must be within the stack and above or equal sp - if (!thread->is_in_stack_range_incl(unextended_sp, sp)) { + // unextended sp must be within the stack + // Note: sp can be greater than unextended_sp in the case of + // interpreted -> interpreted calls that go through a method handle linker, + // since those pop the last argument (the appendix) from the stack. + if (!thread->is_in_stack_range_incl(unextended_sp, sp - Interpreter::stackElementSize)) { return false; } diff --git a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/libAsyncGetCallTraceTest.cpp b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/libAsyncGetCallTraceTest.cpp index ec52277cbbe..e8886f4bb67 100644 --- a/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/libAsyncGetCallTraceTest.cpp +++ b/test/hotspot/jtreg/serviceability/AsyncGetCallTrace/libAsyncGetCallTraceTest.cpp @@ -230,7 +230,40 @@ Java_MyPackage_ASGCTBaseTest_checkAsyncGetCallTraceCall(JNIEnv* env, jclass cls) return false; } - return strcmp(name.get(), "checkAsyncGetCallTraceCall") == 0; + if (strcmp(name.get(), "checkAsyncGetCallTraceCall") != 0) { + fprintf(stderr, "Name is not checkAsyncGetCallTraceCall: %s\n", name.get()); + return false; + } + + // AsyncGetCallTrace and GetStackTrace should return comparable frames + // so we obtain the frames using GetStackTrace and compare them. + + jthread thread; + jvmti->GetCurrentThread(&thread); + jvmtiFrameInfo gstFrames[MAX_DEPTH]; + jint gstCount = 0; + + jvmti->GetStackTrace(thread, 0, MAX_DEPTH, gstFrames, &gstCount); + + if (gstCount != trace.num_frames) { + fprintf(stderr, "GetStackTrace and AsyncGetCallTrace return different number of frames: %d vs %d)", gstCount, trace.num_frames); + return false; + } + + for (int i = 0; i < trace.num_frames; ++i) { + if (trace.frames[i].lineno == -3) { + if (gstFrames[i].location != -1) { + fprintf(stderr, "%d: ASGCT found native frame but GST did not\n", i); + return false; + } + } else { + if (gstFrames[i].method != trace.frames[i].method_id) { + fprintf(stderr, "%d: method_id mismatch: %p vs %p\n", i, gstFrames[i].method, trace.frames[i].method_id); + return false; + } + } + } + return true; } } From c6805e643faf3776bb1779fe6f045e7a20a220de Mon Sep 17 00:00:00 2001 From: Ravali Yatham Date: Thu, 16 Mar 2023 21:31:39 +0000 Subject: [PATCH 007/217] 8302791: Add specific ClassLoader object to Proxy IllegalArgumentException message Reviewed-by: mchung, phh Backport-of: 9f9d678591e02ecaeae7b81eeefb0ba41c7b4dae --- src/java.base/share/classes/java/lang/ClassLoader.java | 5 +++++ src/java.base/share/classes/java/lang/System.java | 4 ++++ src/java.base/share/classes/java/lang/reflect/Proxy.java | 2 +- .../share/classes/jdk/internal/access/JavaLangAccess.java | 6 ++++++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index 7ad0f619101..c1caeb18cd1 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -406,6 +406,11 @@ private static String nameAndId(ClassLoader ld) { return nid; } + // Returns nameAndId string for exception message printing + String nameAndId() { + return nameAndId; + } + /** * Creates a new class loader of the specified name and using the * specified parent class loader for delegation. diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 74cc41870ee..c78014a9c95 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -2451,6 +2451,10 @@ public long findNative(ClassLoader loader, String entry) { public void exit(int statusCode) { Shutdown.exit(statusCode); } + + public String getLoaderNameID(ClassLoader loader) { + return loader.nameAndId(); + } }); } } diff --git a/src/java.base/share/classes/java/lang/reflect/Proxy.java b/src/java.base/share/classes/java/lang/reflect/Proxy.java index 32aed2448b8..a56f2ddef9d 100644 --- a/src/java.base/share/classes/java/lang/reflect/Proxy.java +++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java @@ -881,7 +881,7 @@ private static void ensureVisible(ClassLoader ld, Class c) { } if (type != c) { throw new IllegalArgumentException(c.getName() + - " referenced from a method is not visible from class loader"); + " referenced from a method is not visible from class loader: " + JLA.getLoaderNameID(ld)); } } diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index b68490ad7a3..1a76efc206d 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -410,4 +410,10 @@ public interface JavaLangAccess { * @param statusCode the status code */ void exit(int statusCode); + + /** + * Returns '' @ if classloader has a name + * explicitly set otherwise @ + */ + String getLoaderNameID(ClassLoader loader); } From fba6dd8b454d14b0ae6ce84587c1e4f0358f115d Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 17 Mar 2023 08:05:49 +0000 Subject: [PATCH 008/217] 8301050: Detect Xen Virtualization on Linux aarch64 Reviewed-by: clanger Backport-of: 11804b246e8643a3465b9549794ccfb24ccd8fc5 --- .../cpu/aarch64/vm_version_aarch64.cpp | 36 +++++++++++++------ .../share/runtime/abstract_vm_version.hpp | 5 +-- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 31dfb772759..e92f44b8e49 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -493,26 +493,40 @@ void VM_Version::initialize() { UNSUPPORTED_OPTION(CriticalJNINatives); } -void VM_Version::check_virtualizations() { #if defined(LINUX) - const char* info_file = "/sys/devices/virtual/dmi/id/product_name"; - // check for various strings in the dmi data indicating virtualizations +static bool check_info_file(const char* fpath, + const char* virt1, VirtualizationType vt1, + const char* virt2, VirtualizationType vt2) { char line[500]; - FILE* fp = os::fopen(info_file, "r"); + FILE* fp = os::fopen(fpath, "r"); if (fp == nullptr) { - return; + return false; } while (fgets(line, sizeof(line), fp) != nullptr) { - if (strcasestr(line, "KVM") != 0) { - Abstract_VM_Version::_detected_virtualization = KVM; - break; + if (strcasestr(line, virt1) != 0) { + Abstract_VM_Version::_detected_virtualization = vt1; + fclose(fp); + return true; } - if (strcasestr(line, "VMware") != 0) { - Abstract_VM_Version::_detected_virtualization = VMWare; - break; + if (virt2 != NULL && strcasestr(line, virt2) != 0) { + Abstract_VM_Version::_detected_virtualization = vt2; + fclose(fp); + return true; } } fclose(fp); + return false; +} +#endif + +void VM_Version::check_virtualizations() { +#if defined(LINUX) + const char* pname_file = "/sys/devices/virtual/dmi/id/product_name"; + const char* tname_file = "/sys/hypervisor/type"; + if (check_info_file(pname_file, "KVM", KVM, "VMWare", VMWare)) { + return; + } + check_info_file(tname_file, "Xen", XenHVM, NULL, NoDetectedVirtualization); #endif } diff --git a/src/hotspot/share/runtime/abstract_vm_version.hpp b/src/hotspot/share/runtime/abstract_vm_version.hpp index fd57a35e287..0f3a51ca79f 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.hpp +++ b/src/hotspot/share/runtime/abstract_vm_version.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -71,9 +71,10 @@ class Abstract_VM_Version: AllStatic { static int _vm_build_number; static unsigned int _data_cache_line_flush_size; + public: + static VirtualizationType _detected_virtualization; - public: // Called as part of the runtime services initialization which is // called from the management module initialization (via init_globals()) // after argument parsing and attaching of the main thread has From c00568255be4fef9183ee9650775702efff43d43 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Fri, 17 Mar 2023 08:06:35 +0000 Subject: [PATCH 009/217] 8303354: addCertificatesToKeystore in KeystoreImpl.m needs CFRelease call in early potential CHECK_NULL return Backport-of: b51ea4204eaa18687e7712e87cdc92efbddfcb5b --- .../native/libosxsecurity/KeystoreImpl.m | 31 ++++++++++++++----- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m index 3f0c1de962d..c42f0ed5e79 100644 --- a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m +++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -385,16 +385,30 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore) OSErr searchResult = noErr; jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore"); - CHECK_NULL(jc_KeychainStore); + if (jc_KeychainStore == NULL) { + goto errOut; + } + jmethodID jm_createTrustedCertEntry = (*env)->GetMethodID( env, jc_KeychainStore, "createTrustedCertEntry", "(Ljava/lang/String;Ljava/util/List;JJ[B)V"); - CHECK_NULL(jm_createTrustedCertEntry); + if (jm_createTrustedCertEntry == NULL) { + goto errOut; + } + jclass jc_arrayListClass = (*env)->FindClass(env, "java/util/ArrayList"); - CHECK_NULL(jc_arrayListClass); + if (jc_arrayListClass == NULL) { + goto errOut; + } + jmethodID jm_arrayListCons = (*env)->GetMethodID(env, jc_arrayListClass, "", "()V"); - CHECK_NULL(jm_arrayListCons); + if (jm_arrayListCons == NULL) { + goto errOut; + } + jmethodID jm_listAdd = (*env)->GetMethodID(env, jc_arrayListClass, "add", "(Ljava/lang/Object;)Z"); - CHECK_NULL(jm_listAdd); + if (jm_listAdd == NULL) { + goto errOut; + } do { searchResult = SecKeychainSearchCopyNext(keychainItemSearch, &theItem); @@ -425,7 +439,10 @@ static void addCertificatesToKeystore(JNIEnv *env, jobject keyStore) // See KeychainStore::createTrustedCertEntry for content of inputTrust jobject inputTrust = (*env)->NewObject(env, jc_arrayListClass, jm_arrayListCons); - CHECK_NULL(inputTrust); + if (inputTrust == NULL) { + CFRelease(trustSettings); + goto errOut; + } // Dump everything inside trustSettings into inputTrust CFIndex count = CFArrayGetCount(trustSettings); From 752494f31e5366e2592fec2b940e30fb11ac3e81 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Mon, 20 Mar 2023 13:39:11 +0000 Subject: [PATCH 010/217] 8303949: gcc10 warning Linux ppc64le - note: the layout of aggregates containing vectors with 8-byte alignment has changed in GCC 5 Reviewed-by: phh Backport-of: a32ee5dd8b5d0b65b39d7a3f8bedc7c099987f6f --- make/autoconf/flags-cflags.m4 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index ea1d62685db..1168d0085c8 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 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 @@ -188,6 +188,10 @@ AC_DEFUN([FLAGS_SETUP_WARNINGS], WARNINGS_ENABLE_ALL_CXXFLAGS="$WARNINGS_ENABLE_ALL_CFLAGS $WARNINGS_ENABLE_ADDITIONAL_CXX" DISABLED_WARNINGS="unused-parameter unused" + # gcc10/11 on ppc generate lots of abi warnings about layout of aggregates containing vectors + if test "x$OPENJDK_TARGET_CPU_ARCH" = "xppc"; then + DISABLED_WARNINGS="$DISABLED_WARNINGS psabi" + fi ;; clang) From 15674a933e74b1c809e5f8e5682719287f7cfbc4 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Tue, 21 Mar 2023 08:16:30 +0000 Subject: [PATCH 011/217] 8304063: tools/jpackage/share/AppLauncherEnvTest.java fails when checking LD_LIBRARY_PATH Backport-of: ebac7eec8e5923c66a80cbd66e79c354f30a07a3 --- test/jdk/tools/jpackage/share/AppLauncherEnvTest.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java b/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java index 6e7d35d37b7..cc52b285fbe 100644 --- a/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java +++ b/test/jdk/tools/jpackage/share/AppLauncherEnvTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -26,6 +26,7 @@ import java.util.List; import java.util.Optional; import java.util.function.BiFunction; +import java.util.stream.Stream; import jdk.jpackage.test.JPackageCommand; import jdk.jpackage.test.Annotations.Test; import jdk.jpackage.test.Executor; @@ -83,8 +84,10 @@ public static void test() throws Exception { final String expectedEnvVarValue = Optional.ofNullable(System.getenv( envVarName)).orElse("") + File.pathSeparator + appDir; - TKit.assertEquals(expectedEnvVarValue, actualEnvVarValue, String.format( - "Check value of %s env variable", envVarName)); + TKit.assertTextStream(expectedEnvVarValue) + .predicate(TKit.isLinux() ? String::endsWith : String::equals) + .label(String.format("value of %s env variable", envVarName)) + .apply(Stream.of(actualEnvVarValue)); final String javaLibraryPath = getValue.apply(2, "java.library.path"); TKit.assertTrue( From cc170c7b1756ecb42f9540836261b7f7018da5cb Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 21 Mar 2023 16:00:19 +0000 Subject: [PATCH 012/217] 8292301: [REDO v2] C2 crash when allocating array of size too large Reviewed-by: roland, mdoerr Backport-of: 1ea0d6b424c263590fd145913280a180d7ce5fe1 --- .../share/gc/shared/c2/barrierSetC2.hpp | 2 +- .../shenandoah/c2/shenandoahBarrierSetC2.cpp | 2 +- .../shenandoah/c2/shenandoahBarrierSetC2.hpp | 2 +- src/hotspot/share/opto/callnode.cpp | 49 +----------- src/hotspot/share/opto/callnode.hpp | 10 +-- src/hotspot/share/opto/cfgnode.cpp | 11 +++ src/hotspot/share/opto/compile.cpp | 77 +++++++++++------- src/hotspot/share/opto/compile.hpp | 6 +- src/hotspot/share/opto/graphKit.cpp | 16 +++- src/hotspot/share/opto/loopopts.cpp | 15 +++- src/hotspot/share/opto/macro.cpp | 14 +++- src/hotspot/share/opto/macro.hpp | 4 +- src/hotspot/share/opto/phaseX.cpp | 11 +++ src/hotspot/share/opto/split_if.cpp | 13 +-- .../TestAllocArrayAfterAllocNoUse.java | 52 ++++++++++++ .../allocation/TestCCPAllocateArray.java | 53 ++++++++++++ .../TestFailedAllocationBadGraph.java | 80 +++++++++++++++++++ .../allocation/TestNewArrayBadSize.java | 57 +++++++++++++ ...ArrayOutsideLoopValidLengthTestInLoop.java | 69 ++++++++++++++++ 19 files changed, 435 insertions(+), 108 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java create mode 100644 test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java create mode 100644 test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java create mode 100644 test/hotspot/jtreg/compiler/allocation/TestNewArrayBadSize.java create mode 100644 test/hotspot/jtreg/compiler/allocation/TestNewArrayOutsideLoopValidLengthTestInLoop.java diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp index b64a4bf9b98..d5d4e57596a 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp @@ -290,7 +290,7 @@ class BarrierSetC2: public CHeapObj { virtual void verify_gc_barriers(Compile* compile, CompilePhase phase) const {} #endif - virtual bool final_graph_reshaping(Compile* compile, Node* n, uint opcode) const { return false; } + virtual bool final_graph_reshaping(Compile* compile, Node* n, uint opcode, Unique_Node_List& dead_nodes) const { return false; } virtual bool escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const { return false; } virtual bool escape_add_final_edges(ConnectionGraph* conn_graph, PhaseGVN* gvn, Node* n, uint opcode) const { return false; } diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index b18e4c310d7..5af0b91ec19 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -1124,7 +1124,7 @@ bool ShenandoahBarrierSetC2::has_only_shenandoah_wb_pre_uses(Node* n) { return n->outcnt() > 0; } -bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, uint opcode) const { +bool ShenandoahBarrierSetC2::final_graph_reshaping(Compile* compile, Node* n, uint opcode, Unique_Node_List& dead_nodes) const { switch (opcode) { case Op_CallLeaf: case Op_CallLeafNoFP: { diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp index 656b701f278..add752a413a 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp @@ -139,7 +139,7 @@ class ShenandoahBarrierSetC2 : public BarrierSetC2 { #endif virtual Node* ideal_node(PhaseGVN* phase, Node* n, bool can_reshape) const; - virtual bool final_graph_reshaping(Compile* compile, Node* n, uint opcode) const; + virtual bool final_graph_reshaping(Compile* compile, Node* n, uint opcode, Unique_Node_List& dead_nodes) const; virtual bool escape_add_to_con_graph(ConnectionGraph* conn_graph, PhaseGVN* gvn, Unique_Node_List* delayed_worklist, Node* n, uint opcode) const; virtual bool escape_add_final_edges(ConnectionGraph* conn_graph, PhaseGVN* gvn, Node* n, uint opcode) const; diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp index fc0d741945c..a6d50b44770 100644 --- a/src/hotspot/share/opto/callnode.cpp +++ b/src/hotspot/share/opto/callnode.cpp @@ -1654,6 +1654,7 @@ AllocateNode::AllocateNode(Compile* C, const TypeFunc *atype, init_req( KlassNode , klass_node); init_req( InitialTest , initial_test); init_req( ALength , topnode); + init_req( ValidLengthTest , topnode); C->add_macro_node(this); } @@ -1686,54 +1687,6 @@ Node *AllocateNode::make_ideal_mark(PhaseGVN *phase, Node* obj, Node* control, N return mark_node; } -//============================================================================= -Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if (remove_dead_region(phase, can_reshape)) return this; - // Don't bother trying to transform a dead node - if (in(0) && in(0)->is_top()) return NULL; - - const Type* type = phase->type(Ideal_length()); - if (type->isa_int() && type->is_int()->_hi < 0) { - if (can_reshape) { - PhaseIterGVN *igvn = phase->is_IterGVN(); - // Unreachable fall through path (negative array length), - // the allocation can only throw so disconnect it. - Node* proj = proj_out_or_null(TypeFunc::Control); - Node* catchproj = NULL; - if (proj != NULL) { - for (DUIterator_Fast imax, i = proj->fast_outs(imax); i < imax; i++) { - Node *cn = proj->fast_out(i); - if (cn->is_Catch()) { - catchproj = cn->as_Multi()->proj_out_or_null(CatchProjNode::fall_through_index); - break; - } - } - } - if (catchproj != NULL && catchproj->outcnt() > 0 && - (catchproj->outcnt() > 1 || - catchproj->unique_out()->Opcode() != Op_Halt)) { - assert(catchproj->is_CatchProj(), "must be a CatchProjNode"); - Node* nproj = catchproj->clone(); - igvn->register_new_node_with_optimizer(nproj); - - Node *frame = new ParmNode( phase->C->start(), TypeFunc::FramePtr ); - frame = phase->transform(frame); - // Halt & Catch Fire - Node* halt = new HaltNode(nproj, frame, "unexpected negative array length"); - phase->C->root()->add_req(halt); - phase->transform(halt); - - igvn->replace_node(catchproj, phase->C->top()); - return this; - } - } else { - // Can't correct it during regular GVN so register for IGVN - phase->C->record_for_igvn(this); - } - } - return NULL; -} - // Retrieve the length from the AllocateArrayNode. Narrow the type with a // CastII, if appropriate. If we are not allowed to create new nodes, and // a CastII is appropriate, return NULL. diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp index 7c8baefbca9..1017a76a25e 100644 --- a/src/hotspot/share/opto/callnode.hpp +++ b/src/hotspot/share/opto/callnode.hpp @@ -913,6 +913,7 @@ class AllocateNode : public CallNode { KlassNode, // type (maybe dynamic) of the obj. InitialTest, // slow-path test (may be constant) ALength, // array length (or TOP if none) + ValidLengthTest, ParmLimit }; @@ -922,6 +923,7 @@ class AllocateNode : public CallNode { fields[KlassNode] = TypeInstPtr::NOTNULL; fields[InitialTest] = TypeInt::BOOL; fields[ALength] = t; // length (can be a bad length) + fields[ValidLengthTest] = TypeInt::BOOL; const TypeTuple *domain = TypeTuple::make(ParmLimit, fields); @@ -1016,18 +1018,16 @@ class AllocateNode : public CallNode { // class AllocateArrayNode : public AllocateNode { public: - AllocateArrayNode(Compile* C, const TypeFunc *atype, Node *ctrl, Node *mem, Node *abio, - Node* size, Node* klass_node, Node* initial_test, - Node* count_val - ) + AllocateArrayNode(Compile* C, const TypeFunc* atype, Node* ctrl, Node* mem, Node* abio, Node* size, Node* klass_node, + Node* initial_test, Node* count_val, Node* valid_length_test) : AllocateNode(C, atype, ctrl, mem, abio, size, klass_node, initial_test) { init_class_id(Class_AllocateArray); set_req(AllocateNode::ALength, count_val); + set_req(AllocateNode::ValidLengthTest, valid_length_test); } virtual int Opcode() const; - virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); // Dig the length operand out of a array allocation site. Node* Ideal_length() { diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 50de630681c..1d277d1124b 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -2639,6 +2639,17 @@ const Type* CatchNode::Value(PhaseGVN* phase) const { // Rethrows always throw exceptions, never return if (call->entry_point() == OptoRuntime::rethrow_stub()) { f[CatchProjNode::fall_through_index] = Type::TOP; + } else if (call->is_AllocateArray()) { + Node* klass_node = call->in(AllocateNode::KlassNode); + Node* length = call->in(AllocateNode::ALength); + const Type* length_type = phase->type(length); + const Type* klass_type = phase->type(klass_node); + Node* valid_length_test = call->in(AllocateNode::ValidLengthTest); + const Type* valid_length_test_t = phase->type(valid_length_test); + if (length_type == Type::TOP || klass_type == Type::TOP || valid_length_test_t == Type::TOP || + valid_length_test_t->is_int()->is_con(0)) { + f[CatchProjNode::fall_through_index] = Type::TOP; + } } else if( call->req() > TypeFunc::Parms ) { const Type *arg0 = phase->type( call->in(TypeFunc::Parms) ); // Check for null receiver to virtual or interface calls diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index e3de3affbc1..201a1b2344d 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -2871,7 +2871,7 @@ void Compile::eliminate_redundant_card_marks(Node* n) { //------------------------------final_graph_reshaping_impl---------------------- // Implement items 1-5 from final_graph_reshaping below. -void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { +void Compile::final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes) { if ( n->outcnt() == 0 ) return; // dead node uint nop = n->Opcode(); @@ -2922,9 +2922,9 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { } #endif // Count FPU ops and common calls, implements item (3) - bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->final_graph_reshaping(this, n, nop); + bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->final_graph_reshaping(this, n, nop, dead_nodes); if (!gc_handled) { - final_graph_reshaping_main_switch(n, frc, nop); + final_graph_reshaping_main_switch(n, frc, nop, dead_nodes); } // Collect CFG split points @@ -2933,7 +2933,7 @@ void Compile::final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc) { } } -void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& frc, uint nop) { +void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& frc, uint nop, Unique_Node_List& dead_nodes) { switch( nop ) { // Count all float operations that may use FPU case Op_AddF: @@ -3518,22 +3518,8 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f // that input may be a chain of Phis. If those phis have no // other use, then the MemBarAcquire keeps them alive and // register allocation can be confused. - ResourceMark rm; - Unique_Node_List wq; - wq.push(n->in(MemBarNode::Precedent)); + dead_nodes.push(n->in(MemBarNode::Precedent)); n->set_req(MemBarNode::Precedent, top()); - while (wq.size() > 0) { - Node* m = wq.pop(); - if (m->outcnt() == 0 && m != top()) { - for (uint j = 0; j < m->req(); j++) { - Node* in = m->in(j); - if (in != NULL) { - wq.push(in); - } - } - m->disconnect_inputs(this); - } - } } break; } @@ -3606,7 +3592,7 @@ void Compile::final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& f //------------------------------final_graph_reshaping_walk--------------------- // Replacing Opaque nodes with their input in final_graph_reshaping_impl(), // requires that the walk visits a node's inputs before visiting the node. -void Compile::final_graph_reshaping_walk( Node_Stack &nstack, Node *root, Final_Reshape_Counts &frc ) { +void Compile::final_graph_reshaping_walk(Node_Stack& nstack, Node* root, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes) { Unique_Node_List sfpt; frc._visited.set(root->_idx); // first, mark node as visited @@ -3632,7 +3618,7 @@ void Compile::final_graph_reshaping_walk( Node_Stack &nstack, Node *root, Final_ } } else { // Now do post-visit work - final_graph_reshaping_impl( n, frc ); + final_graph_reshaping_impl(n, frc, dead_nodes); if (nstack.is_empty()) break; // finished n = nstack.node(); // Get node from stack @@ -3732,7 +3718,8 @@ bool Compile::final_graph_reshaping() { // Visit everybody reachable! // Allocate stack of size C->live_nodes()/2 to avoid frequent realloc Node_Stack nstack(live_nodes() >> 1); - final_graph_reshaping_walk(nstack, root(), frc); + Unique_Node_List dead_nodes; + final_graph_reshaping_walk(nstack, root(), frc, dead_nodes); // Check for unreachable (from below) code (i.e., infinite loops). for( uint i = 0; i < frc._tests.size(); i++ ) { @@ -3745,7 +3732,7 @@ bool Compile::final_graph_reshaping() { // 'fall-thru' path, so expected kids is 1 less. if (n->is_PCTable() && n->in(0) && n->in(0)->in(0)) { if (n->in(0)->in(0)->is_Call()) { - CallNode *call = n->in(0)->in(0)->as_Call(); + CallNode* call = n->in(0)->in(0)->as_Call(); if (call->entry_point() == OptoRuntime::rethrow_stub()) { required_outcnt--; // Rethrow always has 1 less kid } else if (call->req() > TypeFunc::Parms && @@ -3754,22 +3741,27 @@ bool Compile::final_graph_reshaping() { // detected that the virtual call will always result in a null // pointer exception. The fall-through projection of this CatchNode // will not be populated. - Node *arg0 = call->in(TypeFunc::Parms); + Node* arg0 = call->in(TypeFunc::Parms); if (arg0->is_Type() && arg0->as_Type()->type()->higher_equal(TypePtr::NULL_PTR)) { required_outcnt--; } - } else if (call->entry_point() == OptoRuntime::new_array_Java() && - call->req() > TypeFunc::Parms+1 && - call->is_CallStaticJava()) { - // Check for negative array length. In such case, the optimizer has + } else if (call->entry_point() == OptoRuntime::new_array_Java() || + call->entry_point() == OptoRuntime::new_array_nozero_Java()) { + // Check for illegal array length. In such case, the optimizer has // detected that the allocation attempt will always result in an // exception. There is no fall-through projection of this CatchNode . - Node *arg1 = call->in(TypeFunc::Parms+1); - if (arg1->is_Type() && - arg1->as_Type()->type()->join(TypeInt::POS)->empty()) { + assert(call->is_CallStaticJava(), "static call expected"); + assert(call->req() == call->jvms()->endoff() + 1, "missing extra input"); + uint valid_length_test_input = call->req() - 1; + Node* valid_length_test = call->in(valid_length_test_input); + call->del_req(valid_length_test_input); + if (valid_length_test->find_int_con(1) == 0) { required_outcnt--; } + dead_nodes.push(valid_length_test); + assert(n->outcnt() == required_outcnt, "malformed control flow"); + continue; } } } @@ -3778,6 +3770,16 @@ bool Compile::final_graph_reshaping() { record_method_not_compilable("malformed control flow"); return true; // Not all targets reachable! } + } else if (n->is_PCTable() && n->in(0) && n->in(0)->in(0) && n->in(0)->in(0)->is_Call()) { + CallNode* call = n->in(0)->in(0)->as_Call(); + if (call->entry_point() == OptoRuntime::new_array_Java() || + call->entry_point() == OptoRuntime::new_array_nozero_Java()) { + assert(call->is_CallStaticJava(), "static call expected"); + assert(call->req() == call->jvms()->endoff() + 1, "missing extra input"); + uint valid_length_test_input = call->req() - 1; + dead_nodes.push(call->in(valid_length_test_input)); + call->del_req(valid_length_test_input); // valid length test useless now + } } // Check that I actually visited all kids. Unreached kids // must be infinite loops. @@ -3796,6 +3798,19 @@ bool Compile::final_graph_reshaping() { } } + while (dead_nodes.size() > 0) { + Node* m = dead_nodes.pop(); + if (m->outcnt() == 0 && m != top()) { + for (uint j = 0; j < m->req(); j++) { + Node* in = m->in(j); + if (in != NULL) { + dead_nodes.push(in); + } + } + m->disconnect_inputs(this); + } + } + #ifdef IA32 // If original bytecodes contained a mixture of floats and doubles // check if the optimizer has made it homogenous, item (3). diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index 6e5f2ed2305..858d5e1c7cd 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -1113,9 +1113,9 @@ class Compile : public Phase { #endif // Function calls made by the public function final_graph_reshaping. // No need to be made public as they are not called elsewhere. - void final_graph_reshaping_impl( Node *n, Final_Reshape_Counts &frc); - void final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& frc, uint nop); - void final_graph_reshaping_walk( Node_Stack &nstack, Node *root, Final_Reshape_Counts &frc ); + void final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes); + void final_graph_reshaping_main_switch(Node* n, Final_Reshape_Counts& frc, uint nop, Unique_Node_List& dead_nodes); + void final_graph_reshaping_walk(Node_Stack& nstack, Node* root, Final_Reshape_Counts& frc, Unique_Node_List& dead_nodes); void eliminate_redundant_card_marks(Node* n); // Logic cone optimization. diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp index a3df43c2381..517e3b7894c 100644 --- a/src/hotspot/share/opto/graphKit.cpp +++ b/src/hotspot/share/opto/graphKit.cpp @@ -2730,7 +2730,9 @@ void GraphKit::make_slow_call_ex(Node* call, ciInstanceKlass* ex_klass, bool sep // Make a catch node with just two handlers: fall-through and catch-all Node* i_o = _gvn.transform( new ProjNode(call, TypeFunc::I_O, separate_io_proj) ); Node* catc = _gvn.transform( new CatchNode(control(), i_o, 2) ); - Node* norm = _gvn.transform( new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci) ); + Node* norm = new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci); + _gvn.set_type_bottom(norm); + C->record_for_igvn(norm); Node* excp = _gvn.transform( new CatchProjNode(catc, CatchProjNode::catch_all_index, CatchProjNode::no_handler_bci) ); { PreserveJVMState pjvms(this); @@ -3969,20 +3971,28 @@ Node* GraphKit::new_array(Node* klass_node, // array klass (maybe variable) initial_slow_test = initial_slow_test->as_Bool()->as_int_value(&_gvn); } + const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type(); + Node* valid_length_test = _gvn.intcon(1); + if (ary_type->isa_aryptr()) { + BasicType bt = ary_type->isa_aryptr()->elem()->array_element_basic_type(); + jint max = TypeAryPtr::max_array_length(bt); + Node* valid_length_cmp = _gvn.transform(new CmpUNode(length, intcon(max))); + valid_length_test = _gvn.transform(new BoolNode(valid_length_cmp, BoolTest::le)); + } + // Create the AllocateArrayNode and its result projections AllocateArrayNode* alloc = new AllocateArrayNode(C, AllocateArrayNode::alloc_type(TypeInt::INT), control(), mem, i_o(), size, klass_node, initial_slow_test, - length); + length, valid_length_test); // Cast to correct type. Note that the klass_node may be constant or not, // and in the latter case the actual array type will be inexact also. // (This happens via a non-constant argument to inline_native_newArray.) // In any case, the value of klass_node provides the desired array type. const TypeInt* length_type = _gvn.find_int_type(length); - const TypeOopPtr* ary_type = _gvn.type(klass_node)->is_klassptr()->as_instance_type(); if (ary_type->isa_aryptr() && length_type != NULL) { // Try to get a better type than POS for the size ary_type = ary_type->is_aryptr()->cast_to_size(length_type); diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index c0804ed677c..358ce5b34aa 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1928,7 +1928,13 @@ void PhaseIdealLoop::clone_loop_handle_data_uses(Node* old, Node_List &old_new, // in the loop to break the loop, then test is again outside of the // loop to determine which way the loop exited. // Loop predicate If node connects to Bool node through Opaque1 node. - if (use->is_If() || use->is_CMove() || C->is_predicate_opaq(use) || use->Opcode() == Op_Opaque4) { + // + // If the use is an AllocateArray through its ValidLengthTest input, + // make sure the Bool/Cmp input is cloned down to avoid a Phi between + // the AllocateArray node and its ValidLengthTest input that could cause + // split if to break. + if (use->is_If() || use->is_CMove() || C->is_predicate_opaq(use) || use->Opcode() == Op_Opaque4 || + (use->Opcode() == Op_AllocateArray && use->in(AllocateNode::ValidLengthTest) == old)) { // Since this code is highly unlikely, we lazily build the worklist // of such Nodes to go split. if (!split_if_set) { @@ -2442,9 +2448,10 @@ void PhaseIdealLoop::clone_loop( IdealLoopTree *loop, Node_List &old_new, int dd if (split_if_set) { while (split_if_set->size()) { Node *iff = split_if_set->pop(); - if (iff->in(1)->is_Phi()) { - Node *b = clone_iff(iff->in(1)->as_Phi(), loop); - _igvn.replace_input_of(iff, 1, b); + uint input = iff->Opcode() == Op_AllocateArray ? AllocateNode::ValidLengthTest : 1; + if (iff->in(input)->is_Phi()) { + Node *b = clone_iff(iff->in(input)->as_Phi(), loop); + _igvn.replace_input_of(iff, input, b); } } } diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 673784d2aab..829cc4c8aed 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -1205,7 +1205,8 @@ void PhaseMacroExpand::expand_allocate_common( AllocateNode* alloc, // allocation node to be expanded Node* length, // array length for an array allocation const TypeFunc* slow_call_type, // Type of slow call - address slow_call_address // Address of slow call + address slow_call_address, // Address of slow call + Node* valid_length_test // whether length is valid or not ) { Node* ctrl = alloc->in(TypeFunc::Control); @@ -1391,6 +1392,12 @@ void PhaseMacroExpand::expand_allocate_common( // Copy debug information and adjust JVMState information, then replace // allocate node with the call call->copy_call_debug_info(&_igvn, alloc); + // For array allocations, copy the valid length check to the call node so Compile::final_graph_reshaping() can verify + // that the call has the expected number of CatchProj nodes (in case the allocation always fails and the fallthrough + // path dies). + if (valid_length_test != NULL) { + call->add_req(valid_length_test); + } if (expand_fast_path) { call->set_cnt(PROB_UNLIKELY_MAG(4)); // Same effect as RC_UNCOMMON. } else { @@ -1872,11 +1879,12 @@ Node* PhaseMacroExpand::prefetch_allocation(Node* i_o, Node*& needgc_false, void PhaseMacroExpand::expand_allocate(AllocateNode *alloc) { expand_allocate_common(alloc, NULL, OptoRuntime::new_instance_Type(), - OptoRuntime::new_instance_Java()); + OptoRuntime::new_instance_Java(), NULL); } void PhaseMacroExpand::expand_allocate_array(AllocateArrayNode *alloc) { Node* length = alloc->in(AllocateNode::ALength); + Node* valid_length_test = alloc->in(AllocateNode::ValidLengthTest); InitializeNode* init = alloc->initialization(); Node* klass_node = alloc->in(AllocateNode::KlassNode); ciKlass* k = _igvn.type(klass_node)->is_klassptr()->klass(); @@ -1891,7 +1899,7 @@ void PhaseMacroExpand::expand_allocate_array(AllocateArrayNode *alloc) { } expand_allocate_common(alloc, length, OptoRuntime::new_array_Type(), - slow_call_address); + slow_call_address, valid_length_test); } //-------------------mark_eliminated_box---------------------------------- diff --git a/src/hotspot/share/opto/macro.hpp b/src/hotspot/share/opto/macro.hpp index 413e8d04c4b..6aa44220f31 100644 --- a/src/hotspot/share/opto/macro.hpp +++ b/src/hotspot/share/opto/macro.hpp @@ -92,8 +92,8 @@ class PhaseMacroExpand : public Phase { void expand_allocate_common(AllocateNode* alloc, Node* length, const TypeFunc* slow_call_type, - address slow_call_address); - void yank_initalize_node(InitializeNode* node); + address slow_call_address, + Node* valid_length_test); void yank_alloc_node(AllocateNode* alloc); Node *value_from_mem(Node *mem, Node *ctl, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc); Node *value_from_mem_phi(Node *mem, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc, Node_Stack *value_phis, int level); diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 1600e1f82d7..bb14fcaac6b 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -1642,6 +1642,16 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) { if (imem != NULL) add_users_to_worklist0(imem); } } + // If the ValidLengthTest input changes then the fallthrough path out of the AllocateArray may have become dead. + // CatchNode::Value() is responsible for killing that path. The CatchNode has to be explicitly enqueued for igvn + // to guarantee the change is not missed. + if (use_op == Op_AllocateArray && n == use->in(AllocateNode::ValidLengthTest)) { + Node* p = use->as_AllocateArray()->proj_out_or_null(TypeFunc::Control); + if (p != NULL) { + add_users_to_worklist0(p); + } + } + if (use_op == Op_Initialize) { Node* imem = use->as_Initialize()->proj_out_or_null(TypeFunc::Memory); if (imem != NULL) add_users_to_worklist0(imem); @@ -1808,6 +1818,7 @@ void PhaseCCP::analyze() { // the Catch following the call. It's looking for a non-NULL // receiver to know when to enable the regular fall-through path // in addition to the NullPtrException path + // Same is true if the type of a ValidLengthTest input to an AllocateArrayNode changes. if (m->is_Call()) { for (DUIterator_Fast i2max, i2 = m->fast_outs(i2max); i2 < i2max; i2++) { Node* p = m->fast_out(i2); // Propagate changes to uses diff --git a/src/hotspot/share/opto/split_if.cpp b/src/hotspot/share/opto/split_if.cpp index 012c1a69905..2c474618e46 100644 --- a/src/hotspot/share/opto/split_if.cpp +++ b/src/hotspot/share/opto/split_if.cpp @@ -128,8 +128,8 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) { } } else { // We might see an Opaque1 from a loop limit check here - assert(use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque1, "unexpected node type"); - Node *use_c = use->is_If() ? use->in(0) : get_ctrl(use); + assert(use->is_If() || use->is_CMove() || use->Opcode() == Op_Opaque1 || use->is_AllocateArray(), "unexpected node type"); + Node *use_c = (use->is_If() || use->is_AllocateArray()) ? use->in(0) : get_ctrl(use); if (use_c == blk1 || use_c == blk2) { assert(use->is_CMove(), "unexpected node type"); continue; @@ -166,14 +166,15 @@ bool PhaseIdealLoop::split_up( Node *n, Node *blk1, Node *blk2 ) { --j; } else { // We might see an Opaque1 from a loop limit check here - assert(u->is_If() || u->is_CMove() || u->Opcode() == Op_Opaque1, "unexpected node type"); - assert(u->in(1) == bol, ""); + assert(u->is_If() || u->is_CMove() || u->Opcode() == Op_Opaque1 || u->is_AllocateArray(), "unexpected node type"); + assert(u->is_AllocateArray() || u->in(1) == bol, ""); + assert(!u->is_AllocateArray() || u->in(AllocateNode::ValidLengthTest) == bol, "wrong input to AllocateArray"); // Get control block of either the CMove or the If input - Node *u_ctrl = u->is_If() ? u->in(0) : get_ctrl(u); + Node *u_ctrl = (u->is_If() || u->is_AllocateArray()) ? u->in(0) : get_ctrl(u); assert((u_ctrl != blk1 && u_ctrl != blk2) || u->is_CMove(), "won't converge"); Node *x = bol->clone(); register_new_node(x, u_ctrl); - _igvn.replace_input_of(u, 1, x); + _igvn.replace_input_of(u, u->is_AllocateArray() ? AllocateNode::ValidLengthTest : 1, x); --j; } } diff --git a/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java b/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java new file mode 100644 index 00000000000..e2bc9bfdd16 --- /dev/null +++ b/test/hotspot/jtreg/compiler/allocation/TestAllocArrayAfterAllocNoUse.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. 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. + */ + +/** + * @test + * @bug 8279125 + * @summary fatal error: no reachable node should have no use + * @requires vm.flavor == "server" + * + * @run main/othervm -XX:-BackgroundCompilation -XX:-DoEscapeAnalysis TestAllocArrayAfterAllocNoUse + * + */ + +public class TestAllocArrayAfterAllocNoUse { + private static Object field; + + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + test(); + } + } + + private static void test() { + try { + final TestAllocArrayAfterAllocNoUse o = new TestAllocArrayAfterAllocNoUse(); + } catch (Exception e) { + final int[] array = new int[100]; + field = array; + } + + } +} diff --git a/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java b/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java new file mode 100644 index 00000000000..9e312a79530 --- /dev/null +++ b/test/hotspot/jtreg/compiler/allocation/TestCCPAllocateArray.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. 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. + */ + +/** + * @test + * @bug 8279062 + * @summary C2: assert(t->meet(t0) == t) failed: Not monotonic after JDK-8278413 + * + * @run main/othervm -XX:-BackgroundCompilation TestCCPAllocateArray + * + */ + +public class TestCCPAllocateArray { + public static void main(String[] args) { + for (int i = 0; i < 20_000; i++) { + try { + test(); + } catch (OutOfMemoryError e) { + } + length(42); + } + } + + private static int[] test() { + int i = 2; + for (; i < 4; i *= 2); + return new int[length(i)]; + } + + private static int length(int i) { + return i == 4 ? Integer.MAX_VALUE : 0; + } +} diff --git a/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java b/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java new file mode 100644 index 00000000000..adf51f0f4d5 --- /dev/null +++ b/test/hotspot/jtreg/compiler/allocation/TestFailedAllocationBadGraph.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. 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. + */ + +/* + * @test + * bug 8279219 + * @summary C2 crash when allocating array of size too large + * @requires vm.compiler2.enabled + * @library /test/lib / + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -ea -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:-BackgroundCompilation TestFailedAllocationBadGraph + */ + +import jdk.test.whitebox.WhiteBox; +import java.lang.reflect.Method; +import compiler.whitebox.CompilerWhiteBoxTest; + +public class TestFailedAllocationBadGraph { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + + private static long[] array; + private static int field; + private static volatile int barrier; + + public static void main(String[] args) throws Exception { + run("test1"); + run("test2"); + } + + private static void run(String method) throws Exception { + Method m = TestFailedAllocationBadGraph.class.getDeclaredMethod(method); + WHITE_BOX.enqueueMethodForCompilation(m, CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION); + if (!WHITE_BOX.isMethodCompiled(m) || WHITE_BOX.getMethodCompilationLevel(m) != CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION) { + throw new RuntimeException("should still be compiled"); + } + } + + private static int test1() { + int length = Integer.MAX_VALUE; + try { + array = new long[length]; + } catch (OutOfMemoryError outOfMemoryError) { + barrier = 0x42; + length = field; + } + return length; + } + + private static int test2() { + int length = -1; + try { + array = new long[length]; + } catch (OutOfMemoryError outOfMemoryError) { + barrier = 0x42; + length = field; + } + return length; + } +} diff --git a/test/hotspot/jtreg/compiler/allocation/TestNewArrayBadSize.java b/test/hotspot/jtreg/compiler/allocation/TestNewArrayBadSize.java new file mode 100644 index 00000000000..3433ca16d91 --- /dev/null +++ b/test/hotspot/jtreg/compiler/allocation/TestNewArrayBadSize.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. 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. + */ + +/* + * @test + * bug 8288184 + * @summary C2 compilation asserts with "Bad graph detected in compute_lca_of_uses" + * @run main/othervm -XX:-BackgroundCompilation TestNewArrayBadSize + */ + +public class TestNewArrayBadSize { + long instanceCount; + int iFld; + + void vMeth(int i, long l) { + int i1, i19 = -845; + for (i1 = 5; i1 > 1; i1 -= 2) + try { + int ax$0 = i19; + try { + for (Object temp = new byte[i19]; ; i19 = "1".equals("0") ? 2 : 1) {} + } finally { + i19 = ax$0; + } + } catch (Throwable ax$3) { + } + } + + void mainTest(String[] strArr1) { + vMeth(iFld, instanceCount); + } + + public static void main(String[] strArr) { + TestNewArrayBadSize _instance = new TestNewArrayBadSize(); + for (int i = 0; i < 10_000; ++i) _instance.mainTest(strArr); + } +} diff --git a/test/hotspot/jtreg/compiler/allocation/TestNewArrayOutsideLoopValidLengthTestInLoop.java b/test/hotspot/jtreg/compiler/allocation/TestNewArrayOutsideLoopValidLengthTestInLoop.java new file mode 100644 index 00000000000..9e64fb66539 --- /dev/null +++ b/test/hotspot/jtreg/compiler/allocation/TestNewArrayOutsideLoopValidLengthTestInLoop.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. 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. + */ + +/* + * @test + * @bug 8291665 + * @summary C2: assert compiling SSLEngineInputRecord::decodeInputRecord + * @run main/othervm -Xbatch TestNewArrayOutsideLoopValidLengthTestInLoop + */ + +import java.util.Arrays; + +public class TestNewArrayOutsideLoopValidLengthTestInLoop { + private static volatile int barrier; + + public static void main(String[] args) { + boolean[] allFalse = new boolean[100]; + boolean[] allTrue = new boolean[100]; + Arrays.fill(allTrue, true); + for (int i = 0; i < 20_000; i++) { + test1(allFalse, allFalse, true); + test1(allTrue, allFalse, true); + test1(allFalse, allTrue, true); + test1(allFalse, allFalse, false); + } + } + + private static int[] test1(boolean[] flags1, boolean[] flags2, boolean flag) { + for (int i = 1; i < 100; i *= 2) { + boolean f = false; + int j = i; + if (flags1[i]) { + barrier = 1; + f = true; + j = i / 2; + } + if (flag) { + barrier = 1; + } + if (f) { + return new int[j]; + } + if (flags2[i]) { + return new int[j]; + } + } + return null; + } +} From 3b64bdeaba38beee93e240d9b3f236dd160e4425 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Wed, 22 Mar 2023 13:09:07 +0000 Subject: [PATCH 013/217] 8303576: addIdentitiesToKeystore in KeystoreImpl.m needs CFRelease call in early potential CHECK_NULL return Backport-of: a7e308ab6e5dba7df790840d29fc7edbf3af2e24 --- .../macosx/native/libosxsecurity/KeystoreImpl.m | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m index c42f0ed5e79..38362709d27 100644 --- a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m +++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m @@ -285,9 +285,14 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore) OSErr searchResult = noErr; jclass jc_KeychainStore = (*env)->FindClass(env, "apple/security/KeychainStore"); - CHECK_NULL(jc_KeychainStore); + if (jc_KeychainStore == NULL) { + goto errOut; + } jmethodID jm_createKeyEntry = (*env)->GetMethodID(env, jc_KeychainStore, "createKeyEntry", "(Ljava/lang/String;JJ[J[[B)V"); - CHECK_NULL(jm_createKeyEntry); + if (jm_createKeyEntry == NULL) { + goto errOut; + } + do { searchResult = SecIdentitySearchCopyNext(identitySearch, &theIdentity); From 8a2425d35d215fc7b17f0d05f003d9bc5dc9c04c Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 23 Mar 2023 08:48:46 +0000 Subject: [PATCH 014/217] 8300042: Improve CPU related JFR events descriptions Backport-of: e326b86d37cec3b395b88598cf30ce4239732a15 --- src/hotspot/share/jfr/metadata/metadata.xml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/jfr/metadata/metadata.xml b/src/hotspot/share/jfr/metadata/metadata.xml index 6d7e5cf6b3f..e30bfe2b826 100644 --- a/src/hotspot/share/jfr/metadata/metadata.xml +++ b/src/hotspot/share/jfr/metadata/metadata.xml @@ -709,7 +709,9 @@ - + @@ -717,14 +719,18 @@ - + - + From 04e337cdb9dad721dc6f126f99378f7073fffb55 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 23 Mar 2023 08:58:15 +0000 Subject: [PATCH 015/217] 8303575: adjust Xen handling on Linux aarch64 Reviewed-by: clanger Backport-of: 8eaf84f09476b08ed421efe74d7554e2b29bc5a7 --- src/hotspot/cpu/aarch64/vm_version_aarch64.cpp | 16 +++++++++------- .../share/jfr/periodic/jfrOSInterface.cpp | 4 +++- .../share/runtime/abstract_vm_version.hpp | 1 + 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index e92f44b8e49..9f33e7526fe 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -526,17 +526,19 @@ void VM_Version::check_virtualizations() { if (check_info_file(pname_file, "KVM", KVM, "VMWare", VMWare)) { return; } - check_info_file(tname_file, "Xen", XenHVM, NULL, NoDetectedVirtualization); + check_info_file(tname_file, "Xen", XenPVHVM, NULL, NoDetectedVirtualization); #endif } void VM_Version::print_platform_virtualization_info(outputStream* st) { #if defined(LINUX) - VirtualizationType vrt = VM_Version::get_detected_virtualization(); - if (vrt == KVM) { - st->print_cr("KVM virtualization detected"); - } else if (vrt == VMWare) { - st->print_cr("VMWare virtualization detected"); - } + VirtualizationType vrt = VM_Version::get_detected_virtualization(); + if (vrt == KVM) { + st->print_cr("KVM virtualization detected"); + } else if (vrt == VMWare) { + st->print_cr("VMWare virtualization detected"); + } else if (vrt == XenPVHVM) { + st->print_cr("Xen virtualization detected"); + } #endif } diff --git a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp index 85f6614ff5e..a0aa9154ff5 100644 --- a/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp +++ b/src/hotspot/share/jfr/periodic/jfrOSInterface.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -253,6 +253,8 @@ const char* JfrOSInterface::virtualization_name() { VirtualizationType vrt = VM_Version::get_detected_virtualization(); if (vrt == XenHVM) { return "Xen hardware-assisted virtualization"; + } else if (vrt == XenPVHVM) { + return "Xen optimized paravirtualization"; } else if (vrt == KVM) { return "KVM virtualization"; } else if (vrt == VMWare) { diff --git a/src/hotspot/share/runtime/abstract_vm_version.hpp b/src/hotspot/share/runtime/abstract_vm_version.hpp index 0f3a51ca79f..59c4b299d8e 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.hpp +++ b/src/hotspot/share/runtime/abstract_vm_version.hpp @@ -31,6 +31,7 @@ typedef enum { NoDetectedVirtualization, XenHVM, + XenPVHVM, // mix-mode on Linux aarch64 KVM, VMWare, HyperV, From 6d61fc116f387779e483db58ed7127d4e3f3c6d1 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 24 Mar 2023 17:00:09 +0000 Subject: [PATCH 016/217] 8227257: javax/swing/JFileChooser/4847375/bug4847375.java fails with AssertionError Reviewed-by: phh Backport-of: 78b1686c150aeaa29c5d969b70c9c42c872246a2 --- .../sun/awt/shell/Win32ShellFolder2.java | 4 +- .../awt/shell/Win32ShellFolderManager2.java | 8 +- .../JFileChooser/4847375/bug4847375.java | 6 +- .../FileSystemView/InaccessibleLink.java | 76 +++++++++++++++++++ 4 files changed, 88 insertions(+), 6 deletions(-) create mode 100644 test/jdk/javax/swing/JFileChooser/FileSystemView/InaccessibleLink.java diff --git a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java index e2895b30faf..c8fc3a4627e 100644 --- a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java +++ b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolder2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -902,7 +902,7 @@ public Win32ShellFolder2 call() { location = Win32ShellFolderManager2.createShellFolderFromRelativePIDL(getDesktop(), linkLocationPIDL); - } catch (InterruptedException e) { + } catch (InterruptedException | FileNotFoundException e) { // Return null } catch (InternalError e) { // Could be a link to a non-bindable object, such as a network connection diff --git a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index 60d79c3b4d3..c75d7738144 100644 --- a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -108,11 +108,15 @@ static Win32ShellFolder2 createShellFolder(Win32ShellFolder2 parent, File file) } static Win32ShellFolder2 createShellFolderFromRelativePIDL(Win32ShellFolder2 parent, long pIDL) - throws InterruptedException { + throws InterruptedException, FileNotFoundException + { // Walk down this relative pIDL, creating new nodes for each of the entries while (pIDL != 0) { long curPIDL = Win32ShellFolder2.copyFirstPIDLEntry(pIDL); if (curPIDL != 0) { + if (!parent.isDirectory()) { + throw new FileNotFoundException("not a directory"); + } parent = Win32ShellFolder2.createShellFolder(parent, curPIDL); pIDL = Win32ShellFolder2.getNextPIDLEntry(pIDL); } else { diff --git a/test/jdk/javax/swing/JFileChooser/4847375/bug4847375.java b/test/jdk/javax/swing/JFileChooser/4847375/bug4847375.java index ffcb2cd502e..ed719dc1438 100644 --- a/test/jdk/javax/swing/JFileChooser/4847375/bug4847375.java +++ b/test/jdk/javax/swing/JFileChooser/4847375/bug4847375.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -23,12 +23,14 @@ /* * @test - * @bug 4847375 8171363 + * @bug 4847375 8171363 8227257 * @requires (os.family == "windows") * @summary JFileChooser Create New Folder button is disabled incorrectly * @author Pavel Porvatov * @modules java.desktop/sun.awt * java.desktop/sun.awt.shell:+open + * @run main/othervm bug4847375 + * @run main/othervm -ea -esa bug4847375 */ import sun.awt.OSInfo; diff --git a/test/jdk/javax/swing/JFileChooser/FileSystemView/InaccessibleLink.java b/test/jdk/javax/swing/JFileChooser/FileSystemView/InaccessibleLink.java new file mode 100644 index 00000000000..95bb2e1411a --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/FileSystemView/InaccessibleLink.java @@ -0,0 +1,76 @@ +/* + * Copyright Amazon.com Inc. 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. + */ + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; + +import javax.swing.filechooser.FileSystemView; + +/* + * @test + * @bug 8227257 + * @requires (os.family == "windows") + * @summary existing but inaccessible target for a link should be ignored + * @run main/othervm InaccessibleLink + * @run main/othervm -ea -esa InaccessibleLink + */ +public final class InaccessibleLink { + + /** + * The link to the windows-update settings. + */ + private static final byte[] bytes = { + 76, 0, 0, 0, 1, 20, 2, 0, 0, 0, 0, 0, -64, 0, 0, 0, 0, 0, 0, 70, + -127, 0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 84, 0, 20, 0, 31, 104, -128, 83, + 28, -121, -96, 66, 105, 16, -94, -22, 8, 0, 43, 48, 48, -99, 62, 0, + 97, -128, 0, 0, 0, 0, 109, 0, 115, 0, 45, 0, 115, 0, 101, 0, 116, 0, + 116, 0, 105, 0, 110, 0, 103, 0, 115, 0, 58, 0, 119, 0, 105, 0, 110, + 0, 100, 0, 111, 0, 119, 0, 115, 0, 117, 0, 112, 0, 100, 0, 97, 0, + 116, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + public static void main(String[] args) throws IOException { + File file = new File("inaccessible.lnk"); + try { + FileOutputStream fos = new FileOutputStream(file); + fos.write(bytes); + fos.close(); + + FileSystemView fsv = FileSystemView.getFileSystemView(); + if (!fsv.isLink(file)) { + throw new RuntimeException("not a link"); + } + File linkLocation = fsv.getLinkLocation(file); + if (linkLocation != null) { + throw new RuntimeException( + "location is not null: " + linkLocation); + } + } finally { + Files.deleteIfExists(file.toPath()); + } + } +} From 637155e3a6e21f7a38205252a2f4f47046d06b61 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Fri, 24 Mar 2023 19:03:28 +0000 Subject: [PATCH 017/217] 8303102: jcmd: ManagementAgent.status truncates the text longer than O_BUFLEN Backport-of: a43931b79cb25d218e8f9b4d4f3a106f59cb2d37 --- src/hotspot/share/services/diagnosticCommand.cpp | 3 ++- .../jdk/sun/management/jmxremote/startstop/JMXStatusTest.java | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 51f47421c50..08e08a7f844 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -800,7 +800,8 @@ void JMXStatusDCmd::execute(DCmdSource source, TRAPS) { if (str != NULL) { char* out = java_lang_String::as_utf8_string(str); if (out) { - output()->print_cr("%s", out); + // Avoid using print_cr() because length maybe longer than O_BUFLEN + output()->print_raw_cr(out); return; } } diff --git a/test/jdk/sun/management/jmxremote/startstop/JMXStatusTest.java b/test/jdk/sun/management/jmxremote/startstop/JMXStatusTest.java index 4a4dffddd9b..0813be10bff 100644 --- a/test/jdk/sun/management/jmxremote/startstop/JMXStatusTest.java +++ b/test/jdk/sun/management/jmxremote/startstop/JMXStatusTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -33,7 +33,7 @@ /** * @test - * @bug 8023093 8138748 8142398 + * @bug 8023093 8138748 8142398 8303102 * @summary Performs a sanity test for the ManagementAgent.status diagnostic command. * Management agent may be disabled, started (only local connections) and started. * The test asserts that the expected text is being printed. From c6a35f50b35c15dbbd6efd45c3a286e06ebabe80 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Mon, 27 Mar 2023 18:04:42 +0000 Subject: [PATCH 018/217] 8302849: SurfaceManager might expose partially constructed object Backport-of: 63ef2143289f4aac52c8b2a6b555ed2b33dc1c07 --- .../share/classes/sun/awt/image/SurfaceManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java b/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java index fe0fd6e787d..bb327889a86 100644 --- a/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java +++ b/src/java.desktop/share/classes/sun/awt/image/SurfaceManager.java @@ -89,7 +89,7 @@ public static void setManager(Image img, SurfaceManager mgr) { imgaccessor.setSurfaceManager(img, mgr); } - private ConcurrentHashMap cacheMap; + private volatile ConcurrentHashMap cacheMap; /** * Return an arbitrary cached object for an arbitrary cache key. From ac0b7c9371f202748d2ee9df79aeae0005cbad7a Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 28 Mar 2023 12:07:08 +0000 Subject: [PATCH 019/217] 8268288: jdk/jfr/api/consumer/streaming/TestOutOfProcessMigration.java fails with "Error: ShouldNotReachHere()" Reviewed-by: mbaesken Backport-of: 0a0909263194032ae7d8348484e3638f84090233 --- src/hotspot/share/cds/filemap.cpp | 34 +++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index ca9ef15acb4..c21625b7378 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -2347,28 +2347,28 @@ void FileMapInfo::stop_sharing_and_unmap(const char* msg) { ClassPathEntry** FileMapInfo::_classpath_entries_for_jvmti = NULL; ClassPathEntry* FileMapInfo::get_classpath_entry_for_jvmti(int i, TRAPS) { + if (i == 0) { + // index 0 corresponds to the ClassPathImageEntry which is a globally shared object + // and should never be deleted. + return ClassLoader::get_jrt_entry(); + } ClassPathEntry* ent = _classpath_entries_for_jvmti[i]; if (ent == NULL) { - if (i == 0) { - ent = ClassLoader::get_jrt_entry(); - assert(ent != NULL, "must be"); - } else { - SharedClassPathEntry* scpe = shared_path(i); - assert(scpe->is_jar(), "must be"); // other types of scpe will not produce archived classes + SharedClassPathEntry* scpe = shared_path(i); + assert(scpe->is_jar(), "must be"); // other types of scpe will not produce archived classes - const char* path = scpe->name(); - struct stat st; - if (os::stat(path, &st) != 0) { + const char* path = scpe->name(); + struct stat st; + if (os::stat(path, &st) != 0) { + char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); + jio_snprintf(msg, strlen(path) + 127, "error in finding JAR file %s", path); + THROW_MSG_(vmSymbols::java_io_IOException(), msg, NULL); + } else { + ent = ClassLoader::create_class_path_entry(THREAD, path, &st, false, false); + if (ent == NULL) { char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); - jio_snprintf(msg, strlen(path) + 127, "error in finding JAR file %s", path); + jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path); THROW_MSG_(vmSymbols::java_io_IOException(), msg, NULL); - } else { - ent = ClassLoader::create_class_path_entry(THREAD, path, &st, false, false); - if (ent == NULL) { - char *msg = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, strlen(path) + 128); - jio_snprintf(msg, strlen(path) + 127, "error in opening JAR file %s", path); - THROW_MSG_(vmSymbols::java_io_IOException(), msg, NULL); - } } } From 268a6a5a3143d26e5a2ec557874e2e903185df42 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Wed, 29 Mar 2023 07:17:50 +0000 Subject: [PATCH 020/217] 8282077: PKCS11 provider C_sign() impl should handle CKR_BUFFER_TOO_SMALL error Backport-of: d7f31d0d53bfec627edc83ceb75fc6202891e186 --- .../share/native/libj2pkcs11/p11_sign.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_sign.c b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_sign.c index a2b852788e1..f6984093096 100644 --- a/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_sign.c +++ b/src/jdk.crypto.cryptoki/share/native/libj2pkcs11/p11_sign.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -144,11 +144,22 @@ JNIEXPORT jbyteArray JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_C_1Sign TRACE1("DEBUG C_Sign: ret rv=0x%lX\n", rv); + if (rv == CKR_BUFFER_TOO_SMALL) { + bufP = (CK_BYTE_PTR) malloc(ckSignatureLength); + if (bufP == NULL) { + throwOutOfMemoryError(env, 0); + goto cleanup; + } + rv = (*ckpFunctions->C_Sign)(ckSessionHandle, ckpData, ckDataLength, + bufP, &ckSignatureLength); + } + if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { jSignature = ckByteArrayToJByteArray(env, bufP, ckSignatureLength); TRACE1("DEBUG C_Sign: signature length = %lu\n", ckSignatureLength); } +cleanup: free(ckpData); if (bufP != BUF) { free(bufP); } From 7cf28d56a91ccae6d4f51257824a17047975ac51 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Wed, 29 Mar 2023 07:21:24 +0000 Subject: [PATCH 021/217] 8283062: Uninitialized warnings in libgtest with GCC 11.2 Backport-of: a244051a8c967039d7639afcaf83f7d92af49613 --- make/hotspot/lib/CompileGtest.gmk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index cb2bbccc168..f16b9a747bc 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 2022, 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 @@ -49,7 +49,7 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \ $(GTEST_FRAMEWORK_SRC)/googletest/src \ $(GTEST_FRAMEWORK_SRC)/googlemock/src, \ INCLUDE_FILES := gtest-all.cc gmock-all.cc, \ - DISABLED_WARNINGS_gcc := undef unused-result format-nonliteral, \ + DISABLED_WARNINGS_gcc := undef unused-result format-nonliteral maybe-uninitialized, \ DISABLED_WARNINGS_clang := undef unused-result format-nonliteral, \ CFLAGS := $(JVM_CFLAGS) \ -I$(GTEST_FRAMEWORK_SRC)/googletest \ From 6ba50fcf822d26b2a1777e7803f3220ec7b01f93 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Wed, 29 Mar 2023 07:23:18 +0000 Subject: [PATCH 022/217] 8286287: Reading file as UTF-16 causes Error which "shouldn't happen" Backport-of: cc7560e995eac56709d9e55a1561135fad246cb2 --- .../share/classes/java/lang/String.java | 4 +- .../jdk/java/lang/String/NewStringNoRepl.java | 50 +++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 test/jdk/java/lang/String/NewStringNoRepl.java diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 905f61c4b12..a0b2a025388 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -651,8 +651,6 @@ public String(byte[] bytes, int offset, int length, Charset charset) { // decode using CharsetDecoder int en = scale(length, cd.maxCharsPerByte()); - cd.onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); char[] ca = new char[en]; if (charset.getClass().getClassLoader0() != null && System.getSecurityManager() != null) { @@ -1197,6 +1195,8 @@ private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int private static int decodeWithDecoder(CharsetDecoder cd, char[] dst, byte[] src, int offset, int length) { ByteBuffer bb = ByteBuffer.wrap(src, offset, length); CharBuffer cb = CharBuffer.wrap(dst, 0, dst.length); + cd.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); try { CoderResult cr = cd.decode(bb, cb, true); if (!cr.isUnderflow()) diff --git a/test/jdk/java/lang/String/NewStringNoRepl.java b/test/jdk/java/lang/String/NewStringNoRepl.java new file mode 100644 index 00000000000..ae1a26393cc --- /dev/null +++ b/test/jdk/java/lang/String/NewStringNoRepl.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022, 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. + */ + +/* + * @test + * @bug 8286287 + * @summary Verifies newStringNoRepl() does not throw an Error. + */ + +import java.io.IOException; +import java.nio.file.Files; +import java.util.HexFormat; +import static java.nio.charset.StandardCharsets.UTF_16; + +public class NewStringNoRepl { + private final static byte[] MALFORMED_UTF16 = {(byte)0x00, (byte)0x20, (byte)0x00}; + + public static void main(String... args) throws IOException { + var f = Files.createTempFile(null, null); + try (var fos = Files.newOutputStream(f)) { + fos.write(MALFORMED_UTF16); + } + System.out.println("Returned bytes: " + + HexFormat.of() + .withPrefix("x") + .withUpperCase() + .formatHex(Files.readString(f, UTF_16).getBytes(UTF_16))); + Files.delete(f); + } +} From 59d821177de36330d14416f5359f0c0ac3242427 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Wed, 29 Mar 2023 07:25:20 +0000 Subject: [PATCH 023/217] 8287541: Files.writeString fails to throw IOException for charset "windows-1252" Backport-of: 6fb84e2c9119bdb9c66dd49422bcab637bbd4008 --- .../share/classes/java/lang/String.java | 7 ++---- .../java/nio/file/Files/ReadWriteString.java | 22 ++++++++----------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index a0b2a025388..884a117727e 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -833,7 +833,8 @@ private static byte[] encodeWithEncoder(Charset cs, byte coder, byte[] val, bool CharsetEncoder ce = cs.newEncoder(); int len = val.length >> coder; // assume LATIN1=0/UTF16=1; int en = scale(len, ce.maxBytesPerChar()); - if (ce instanceof ArrayEncoder ae) { + // fastpath with ArrayEncoder implies `doReplace`. + if (doReplace && ce instanceof ArrayEncoder ae) { // fastpath for ascii compatible if (coder == LATIN1 && ae.isASCIICompatible() && @@ -844,10 +845,6 @@ private static byte[] encodeWithEncoder(Charset cs, byte coder, byte[] val, bool if (len == 0) { return ba; } - if (doReplace) { - ce.onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - } int blen = (coder == LATIN1) ? ae.encodeFromLatin1(val, 0, len, ba) : ae.encodeFromUTF16(val, 0, len, ba); diff --git a/test/jdk/java/nio/file/Files/ReadWriteString.java b/test/jdk/java/nio/file/Files/ReadWriteString.java index 4a5e1ebb629..37c069c6aa9 100644 --- a/test/jdk/java/nio/file/Files/ReadWriteString.java +++ b/test/jdk/java/nio/file/Files/ReadWriteString.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -46,11 +46,12 @@ import org.testng.annotations.Test; /* @test - * @bug 8201276 8205058 8209576 + * @bug 8201276 8205058 8209576 8287541 * @build ReadWriteString PassThroughFileSystem * @run testng ReadWriteString * @summary Unit test for methods for Files readString and write methods. * @key randomness + * @modules jdk.charsets */ @Test(groups = "readwrite") public class ReadWriteString { @@ -60,11 +61,6 @@ public class ReadWriteString { final String TEXT_ASCII = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n abcdefghijklmnopqrstuvwxyz\n 1234567890\n"; private static final String JA_STRING = "\u65e5\u672c\u8a9e\u6587\u5b57\u5217"; - // malformed input: a high surrogate without the low surrogate - static char[] illChars = { - '\u00fa', '\ud800' - }; - static byte[] data = getData(); static byte[] getData() { @@ -98,6 +94,8 @@ public Object[][] getMalformedWrite() throws IOException { {path, "\u00A0\u00A1", US_ASCII}, {path, "\ud800", UTF_8}, {path, JA_STRING, ISO_8859_1}, + {path, "\u041e", Charset.forName("windows-1252")}, // cyrillic capital letter O + {path, "\u091c", Charset.forName("windows-31j")}, // devanagari letter ja }; } @@ -119,7 +117,7 @@ public Object[][] getIllegalInput() throws IOException { * Writes the data using both the existing and new method and compares the results. */ @DataProvider(name = "testWriteString") - public Object[][] getWriteString() throws IOException { + public Object[][] getWriteString() { return new Object[][]{ {testFiles[1], testFiles[2], TEXT_ASCII, US_ASCII, null}, @@ -134,8 +132,7 @@ public Object[][] getWriteString() throws IOException { * Reads the file using both the existing and new method and compares the results. */ @DataProvider(name = "testReadString") - public Object[][] getReadString() throws IOException { - Path path = Files.createTempFile("readString_file1", null); + public Object[][] getReadString() { return new Object[][]{ {testFiles[1], TEXT_ASCII, US_ASCII, US_ASCII}, {testFiles[1], TEXT_ASCII, US_ASCII, UTF_8}, @@ -267,11 +264,10 @@ public void testMalformedRead(Path path, byte[] data, Charset csWrite, Charset c path.toFile().deleteOnExit(); String temp = new String(data, csWrite); Files.writeString(path, temp, csWrite, CREATE); - String s; if (csRead == null) { - s = Files.readString(path); + Files.readString(path); } else { - s = Files.readString(path, csRead); + Files.readString(path, csRead); } } From ec7f16985a0ac78a99799f45f27c8926e4102479 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Wed, 29 Mar 2023 07:28:32 +0000 Subject: [PATCH 024/217] 8291637: HttpClient default keep alive timeout not followed if server sends invalid value Backport-of: b17a745d7f55941f02b0bdde83866aa5d32cce07 --- .../classes/sun/net/www/http/HttpClient.java | 8 + .../net/www/http/KeepAliveCache/B8291637.java | 139 ++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 test/jdk/sun/net/www/http/KeepAliveCache/B8291637.java diff --git a/src/java.base/share/classes/sun/net/www/http/HttpClient.java b/src/java.base/share/classes/sun/net/www/http/HttpClient.java index a603badb0c6..ea24babffbd 100644 --- a/src/java.base/share/classes/sun/net/www/http/HttpClient.java +++ b/src/java.base/share/classes/sun/net/www/http/HttpClient.java @@ -897,7 +897,15 @@ private boolean parseHTTPHeader(MessageHeader responses, ProgressSource pi, Http responses.findValue("Keep-Alive")); /* default should be larger in case of proxy */ keepAliveConnections = p.findInt("max", usingProxy?50:5); + if (keepAliveConnections < 0) { + keepAliveConnections = usingProxy?50:5; + } keepAliveTimeout = p.findInt("timeout", -1); + if (keepAliveTimeout < -1) { + // if the server specified a negative (invalid) value + // then we set to -1, which is equivalent to no value + keepAliveTimeout = -1; + } } } else if (b[7] != '0') { /* diff --git a/test/jdk/sun/net/www/http/KeepAliveCache/B8291637.java b/test/jdk/sun/net/www/http/KeepAliveCache/B8291637.java new file mode 100644 index 00000000000..6ba25724123 --- /dev/null +++ b/test/jdk/sun/net/www/http/KeepAliveCache/B8291637.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2022, 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. + */ + +/* + * @test + * @bug 8291637 + * @run main/othervm -Dhttp.keepAlive.time.server=20 -esa -ea B8291637 timeout + * @run main/othervm -Dhttp.keepAlive.time.server=20 -esa -ea B8291637 max + */ + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.*; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.CompletableFuture; + +public class B8291637 { + static CompletableFuture passed = new CompletableFuture<>(); + + static class Server extends Thread { + final ServerSocket serverSocket; + final int port; + final String param; // the parameter to test "max" or "timeout" + volatile Socket s; + + public Server(String param) throws IOException { + serverSocket = new ServerSocket(0); + port = serverSocket.getLocalPort(); + setDaemon(true); + this.param = param; + } + + public int getPort() { + return port; + } + + public void close() { + try { + serverSocket.close(); + if (s != null) + s.close(); + } catch (IOException e) {} + } + + static void readRequest(Socket s) throws IOException { + InputStream is = s.getInputStream(); + is.read(); + while (is.available() > 0) + is.read(); + } + + public void run() { + try { + while (true) { + s = serverSocket.accept(); + readRequest(s); + OutputStream os = s.getOutputStream(); + String resp = "" + + "HTTP/1.1 200 OK\r\n" + + "Content-Length: 11\r\n" + + "Connection: Keep-Alive\r\n" + + "Keep-Alive: " + param + "=-10\r\n" + // invalid negative value + "\r\n" + + "Hello World"; + os.write(resp.getBytes(StandardCharsets.ISO_8859_1)); + os.flush(); + InputStream is = s.getInputStream(); + long l1 = System.currentTimeMillis(); + is.read(); + long l2 = System.currentTimeMillis(); + long diff = (l2 - l1) / 1000; + /* + * timeout is set to 20 seconds. If bug is still present + * then the timeout will occur the first time the keep alive + * thread wakes up which is after 5 seconds. This allows + * very large leeway with slow running hardware. + * + * Same behavior should occur in case of max=-1 with the bug + */ + if (diff < 19) { + passed.complete(false); + } else { + passed.complete(true); + } + System.out.println("Time diff = " + diff); + } + } catch (Throwable t) { + System.err.println("Server exception terminating: " + t); + passed.completeExceptionally(t); + } + } + } + + public static void main(String[] args) throws Exception { + Server server = new Server(args[0]); + int port = server.getPort(); + server.start(); + URL url = new URL("http://127.0.0.1:" + Integer.toString(port) + "/"); + HttpURLConnection urlc = (HttpURLConnection) url.openConnection(); + InputStream i = urlc.getInputStream(); + int c,count=0; + byte[] buf = new byte[256]; + while ((c=i.read(buf)) != -1) { + count+=c; + } + i.close(); + System.out.println("Read " + count ); + try { + if (!passed.get()) { + throw new RuntimeException("Test failed"); + } else { + System.out.println("Test passed"); + } + } finally { + server.close(); + } + } +} From a71545b516575a58d4d6719e816b878c7091340c Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Wed, 29 Mar 2023 07:31:39 +0000 Subject: [PATCH 025/217] 8291226: Create Test Cases to cover scenarios for JDK-8278067 Backport-of: 86ec158dfb7a770fe9a74ff8617bac938d0bb90f --- .../www/http/HttpClient/KeepAliveTest.java | 1277 +++++++++++++++++ 1 file changed, 1277 insertions(+) create mode 100644 test/jdk/sun/net/www/http/HttpClient/KeepAliveTest.java diff --git a/test/jdk/sun/net/www/http/HttpClient/KeepAliveTest.java b/test/jdk/sun/net/www/http/HttpClient/KeepAliveTest.java new file mode 100644 index 00000000000..7ec12a279b4 --- /dev/null +++ b/test/jdk/sun/net/www/http/HttpClient/KeepAliveTest.java @@ -0,0 +1,1277 @@ +/* + * Copyright (c) 2022 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. + */ + +/* + * @test + * @library /test/lib + * @modules java.base/sun.net:+open + * java.base/sun.net.www.http:+open + * java.base/sun.net.www:+open + * java.base/sun.net.www.protocol.http:+open + * @run main/othervm KeepAliveTest 0 + * @run main/othervm KeepAliveTest 1 + * @run main/othervm KeepAliveTest 2 + * @run main/othervm KeepAliveTest 3 + * @run main/othervm KeepAliveTest 4 + * @run main/othervm KeepAliveTest 5 + * @run main/othervm KeepAliveTest 6 + * @run main/othervm KeepAliveTest 7 + * @run main/othervm KeepAliveTest 8 + * @run main/othervm KeepAliveTest 9 + * @run main/othervm KeepAliveTest 10 + * @run main/othervm KeepAliveTest 11 + * @run main/othervm KeepAliveTest 12 + * @run main/othervm KeepAliveTest 13 + * @run main/othervm KeepAliveTest 14 + * @run main/othervm KeepAliveTest 15 + * @run main/othervm KeepAliveTest 16 + * @run main/othervm KeepAliveTest 17 + * @run main/othervm KeepAliveTest 18 + * @run main/othervm KeepAliveTest 19 + * @run main/othervm KeepAliveTest 20 + * @run main/othervm KeepAliveTest 21 + * @run main/othervm KeepAliveTest 22 + * @run main/othervm KeepAliveTest 23 + * @run main/othervm KeepAliveTest 24 + * @run main/othervm KeepAliveTest 25 + * @run main/othervm KeepAliveTest 26 + * @run main/othervm KeepAliveTest 27 + * @run main/othervm KeepAliveTest 28 + * @run main/othervm KeepAliveTest 29 + * @run main/othervm KeepAliveTest 30 + * @run main/othervm KeepAliveTest 31 + * @run main/othervm KeepAliveTest 32 + * @run main/othervm KeepAliveTest 33 + * @run main/othervm KeepAliveTest 34 + * @run main/othervm KeepAliveTest 35 + * @run main/othervm KeepAliveTest 36 + * @run main/othervm KeepAliveTest 37 + * @run main/othervm KeepAliveTest 38 + * @run main/othervm KeepAliveTest 39 + * @run main/othervm KeepAliveTest 40 + * @run main/othervm KeepAliveTest 41 + * @run main/othervm KeepAliveTest 42 + * @run main/othervm KeepAliveTest 43 + * @run main/othervm KeepAliveTest 44 + * @run main/othervm KeepAliveTest 45 + * @run main/othervm KeepAliveTest 46 + * @run main/othervm KeepAliveTest 47 + * @run main/othervm KeepAliveTest 48 + * @run main/othervm KeepAliveTest 49 + * @run main/othervm KeepAliveTest 50 + * @run main/othervm KeepAliveTest 51 + * @run main/othervm KeepAliveTest 52 + * @run main/othervm KeepAliveTest 53 + * @run main/othervm KeepAliveTest 54 + * @run main/othervm KeepAliveTest 55 + * @run main/othervm KeepAliveTest 56 + * @run main/othervm KeepAliveTest 57 + * @run main/othervm KeepAliveTest 58 + * @run main/othervm KeepAliveTest 59 + * @run main/othervm KeepAliveTest 60 + * @run main/othervm KeepAliveTest 61 + * @run main/othervm KeepAliveTest 62 + * @run main/othervm KeepAliveTest 63 + * @run main/othervm KeepAliveTest 64 + * @run main/othervm KeepAliveTest 65 + * @run main/othervm KeepAliveTest 66 + * @run main/othervm KeepAliveTest 67 + * @run main/othervm KeepAliveTest 68 + * @run main/othervm KeepAliveTest 69 + * @run main/othervm KeepAliveTest 70 + * @run main/othervm KeepAliveTest 71 + * @run main/othervm KeepAliveTest 72 + * @run main/othervm KeepAliveTest 73 + * @run main/othervm KeepAliveTest 74 + * @run main/othervm KeepAliveTest 75 + * @run main/othervm KeepAliveTest 76 + * @run main/othervm KeepAliveTest 77 + * @run main/othervm KeepAliveTest 78 + * @run main/othervm KeepAliveTest 79 + * @run main/othervm KeepAliveTest 80 + * @run main/othervm KeepAliveTest 81 + * @run main/othervm KeepAliveTest 82 + * @run main/othervm KeepAliveTest 83 + * @run main/othervm KeepAliveTest 84 + * @run main/othervm KeepAliveTest 85 + * @run main/othervm KeepAliveTest 86 + * @run main/othervm KeepAliveTest 87 + * @run main/othervm KeepAliveTest 88 + * @run main/othervm KeepAliveTest 89 + * @run main/othervm KeepAliveTest 90 + * @run main/othervm KeepAliveTest 91 + * @run main/othervm KeepAliveTest 92 + * @run main/othervm KeepAliveTest 93 + * @run main/othervm KeepAliveTest 94 + * @run main/othervm KeepAliveTest 95 + * @run main/othervm KeepAliveTest 96 + * @run main/othervm KeepAliveTest 97 + * @run main/othervm KeepAliveTest 98 + * @run main/othervm KeepAliveTest 99 + * @run main/othervm KeepAliveTest 100 + * @run main/othervm KeepAliveTest 101 + * @run main/othervm KeepAliveTest 102 + * @run main/othervm KeepAliveTest 103 + * @run main/othervm KeepAliveTest 104 + * @run main/othervm KeepAliveTest 105 + * @run main/othervm KeepAliveTest 106 + * @run main/othervm KeepAliveTest 107 + * @run main/othervm KeepAliveTest 108 + * @run main/othervm KeepAliveTest 109 + * @run main/othervm KeepAliveTest 110 + * @run main/othervm KeepAliveTest 111 + * @run main/othervm KeepAliveTest 112 + * @run main/othervm KeepAliveTest 113 + * @run main/othervm KeepAliveTest 114 + * @run main/othervm KeepAliveTest 115 + * @run main/othervm KeepAliveTest 116 + * @run main/othervm KeepAliveTest 117 + * @run main/othervm KeepAliveTest 118 + * @run main/othervm KeepAliveTest 119 + * @run main/othervm KeepAliveTest 120 + * @run main/othervm KeepAliveTest 121 + * @run main/othervm KeepAliveTest 122 + * @run main/othervm KeepAliveTest 123 + * @run main/othervm KeepAliveTest 124 + * @run main/othervm KeepAliveTest 125 + * @run main/othervm KeepAliveTest 126 + * @run main/othervm KeepAliveTest 127 + * @run main/othervm KeepAliveTest 128 + * @run main/othervm KeepAliveTest 129 + * @run main/othervm KeepAliveTest 130 + * @run main/othervm KeepAliveTest 131 + * @run main/othervm KeepAliveTest 132 + * @run main/othervm KeepAliveTest 133 + * @run main/othervm KeepAliveTest 134 + * @run main/othervm KeepAliveTest 135 + * @run main/othervm KeepAliveTest 136 + * @run main/othervm KeepAliveTest 137 + * @run main/othervm KeepAliveTest 138 + * @run main/othervm KeepAliveTest 139 + * @run main/othervm KeepAliveTest 140 + * @run main/othervm KeepAliveTest 141 + * @run main/othervm KeepAliveTest 142 + * @run main/othervm KeepAliveTest 143 + * @run main/othervm KeepAliveTest 144 + * @run main/othervm KeepAliveTest 145 + * @run main/othervm KeepAliveTest 146 + * @run main/othervm KeepAliveTest 147 + * @run main/othervm KeepAliveTest 148 + * @run main/othervm KeepAliveTest 149 + * @run main/othervm KeepAliveTest 150 + * @run main/othervm KeepAliveTest 151 + * @run main/othervm KeepAliveTest 152 + * @run main/othervm KeepAliveTest 153 + * @run main/othervm KeepAliveTest 154 + * @run main/othervm KeepAliveTest 155 + * @run main/othervm KeepAliveTest 156 + * @run main/othervm KeepAliveTest 157 + * @run main/othervm KeepAliveTest 158 + * @run main/othervm KeepAliveTest 159 + */ + +import java.nio.charset.StandardCharsets; +import java.io.InputStream; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.Proxy.Type; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.URL; +import java.util.List; +import java.util.Map.Entry; +import java.util.concurrent.CountDownLatch; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; +import sun.net.www.http.HttpClient; +import sun.net.www.http.KeepAliveCache; +import sun.net.www.protocol.http.HttpURLConnection; +import jdk.test.lib.net.URIBuilder; + +public class KeepAliveTest { + private static final Logger logger = Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection"); + private static final String NOT_CACHED = "NotCached"; + private static final String CLIENT_SEPARATOR = ";"; + private static final String NEW_LINE = "\r\n"; + private volatile int SERVER_PORT = 0; + /* + * isProxySet is shared variable between server thread and client thread(main) and it should be set and reset to false for each and + * every scenario. + * isProxySet variable should be set by server thread before proceeding to client thread(main). + */ + private volatile boolean isProxySet = false; + private static final String CONNECTION_KEEP_ALIVE_ONLY = "Connection: keep-alive"; + private static final String PROXY_CONNECTION_KEEP_ALIVE_ONLY = "Proxy-Connection: keep-alive"; + private static final String KEEP_ALIVE_TIMEOUT_NEG = "Keep-alive: timeout=-20"; + private static final String KEEP_ALIVE_TIMEOUT_ZERO = "Keep-alive: timeout=0"; + private static final String KEEP_ALIVE_TIMEOUT = "Keep-alive: timeout=20"; + private static final String KEEP_ALIVE_PROXY_TIMEOUT = "Keep-alive: timeout=120"; + private static final String CLIENT_HTTP_KEEP_ALIVE_TIME_SERVER_NEGATIVE = "http.keepAlive.time.server=-100"; + private static final String CLIENT_HTTP_KEEP_ALIVE_TIME_PROXY_NEGATIVE = "http.keepAlive.time.proxy=-200"; + private static final String CLIENT_HTTP_KEEP_ALIVE_TIME_SERVER_ZERO = "http.keepAlive.time.server=0"; + private static final String CLIENT_HTTP_KEEP_ALIVE_TIME_PROXY_ZERO = "http.keepAlive.time.proxy=0"; + private static final String CLIENT_HTTP_KEEP_ALIVE_TIME_SERVER_POSITIVE = "http.keepAlive.time.server=100"; + private static final String CLIENT_HTTP_KEEP_ALIVE_TIME_PROXY_POSITIVE = "http.keepAlive.time.proxy=200"; + private static final String CONNECTION_KEEP_ALIVE_WITH_TIMEOUT = CONNECTION_KEEP_ALIVE_ONLY + NEW_LINE + + KEEP_ALIVE_TIMEOUT; + /* + * Following Constants represents Client Side Properties and is used as reference in below table as + * CLIENT_INPUT_CONSTANT_NAMES + */ + private static final String SERVER_100_NEGATIVE = CLIENT_HTTP_KEEP_ALIVE_TIME_SERVER_NEGATIVE; + private static final String PROXY_200_NEGATIVE = CLIENT_HTTP_KEEP_ALIVE_TIME_PROXY_NEGATIVE; + private static final String SERVER_ZERO = CLIENT_HTTP_KEEP_ALIVE_TIME_SERVER_ZERO; + private static final String PROXY_ZERO = CLIENT_HTTP_KEEP_ALIVE_TIME_PROXY_ZERO; + private static final String SERVER_100 = CLIENT_HTTP_KEEP_ALIVE_TIME_SERVER_POSITIVE; + private static final String PROXY_200 = CLIENT_HTTP_KEEP_ALIVE_TIME_PROXY_POSITIVE; + + /* + * CONSTANTS A,B,C,D,E,NI,F,G,H,I represents ServerScenarios and is used as reference in below table + * as SERVER_RESPONSE_CONSTANT_NAME + */ + private static final String A = CONNECTION_KEEP_ALIVE_ONLY; + private static final String B = CONNECTION_KEEP_ALIVE_WITH_TIMEOUT; + private static final String C = PROXY_CONNECTION_KEEP_ALIVE_ONLY; + private static final String D = PROXY_CONNECTION_KEEP_ALIVE_ONLY + NEW_LINE + CONNECTION_KEEP_ALIVE_ONLY; + private static final String E = C + NEW_LINE + KEEP_ALIVE_PROXY_TIMEOUT; + private static final String NI = "NO_INPUT"; + private static final String F = A + NEW_LINE + KEEP_ALIVE_TIMEOUT_NEG; + private static final String G = A + NEW_LINE + KEEP_ALIVE_TIMEOUT_ZERO; + private static final String H = C + NEW_LINE + KEEP_ALIVE_TIMEOUT_NEG; + private static final String I = C + NEW_LINE + KEEP_ALIVE_TIMEOUT_ZERO; + + /* + * There are 160 scenarios run by this program. + * For every scenario there is mapping between serverScenarios[int],clientScenarios[int] and expectedOutput[int] + * + * serverScenarios[0] clientScenarios[0] expectedOutput[0] + * serverScenarios[1] clientScenarios[1] expectedOutput[1] + * serverScenarios[2] clientScenarios[2] expectedOutput[2] + * + * ... + * + * serverScenarios[159] cientScenarios[159] expectedOutput[159] + * + * whereas serverScenarios[int] is retrieved using getServerScenario(int) + * whereas clientScenarios[int] is retrieved using clientScenario[getClientScenarioNumber[int]] + * and + * expectedOutput[int] is retrieved using expectedOuput[int] directly. + * + */ + + /* Here is the complete table of server_response, client system properties input and expected cached timeout at client side */ + /* ScNo | SERVER RESPONSE (SERVER_RESPONSE_CONSTANT_NAME)| CLIENT SYSTEM PROPERTIES INPUT (CLIENT_INPUT_CONSTANT_NAMES) | EXPECTED CACHED TIMEOUT AT CLIENT SIDE + ***************************************************************************************************************************************** + * 0 | Connection: keep-alive (A) | No Input Provided (NI) | Default Timeout set to 5 + *--------------------------------------------------------------------------------------------------------------------------- + * 1 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=100 (SERVER_100)| Client Timeout set to 100 + *-------------------------------------------------------------------------------------------------------------------------- + * 2 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.proxy=200 (PROXY_200) | Default Timeout set to 5 + *--------------------------------------------------------------------------------------------------------------------------- + * 3 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 100 + * | | (SERVER_100 && PROXY_200) | + *--------------------------------------------------------------------------------------------------------------------------- + * 4 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=-100 | Default Timeout set to 5 + * | | (SERVER_100_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 5 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.proxy=-200 | Default Timeout set to 5 + * | | (PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 6 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=-100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Default Timeout set to 5 + * | | (SERVER_100_NEGATIVE && PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 7 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=0 | Connection Closed Immediately + * | | (SERVER_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 8 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.proxy=0 | Default Timeout set to 5 + * | | (PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 9 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=0 | Connection Closed Immediately + * | | (SERVER_ZERO && PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 10 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Connection Closed Immediately + * | | (SERVER_ZERO && PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 11 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=-100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | Default Timeout set to 5 + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 12 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | Timeout set to 100 + * | | (SERVER_100 && PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 13 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Connection Closed Immediately + * | | (SERVER_ZERO && PROXY_200) | + *--------------------------------------------------------------------------------------------------------------------------- + * 14 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Timeout set to 100 + * | | (SERVER_100 && PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 15 | Connection: keep-alive (A) | -Dhttp.keepAlive.time.server=-100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Default Timeout set to 5 + * | | (SERVER_100_NEGATIVE && PROXY_200) | + *--------------------------------------------------------------------------------------------------------------------------- + * 16 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | No Input Provided (NI) | Timeout set to 20 + *------------------------------------------------------------------------------------------------------------------------ + * 17 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=100 | Timeout set to 20 + * | | (SERVER_100) | + *--------------------------------------------------------------------------------------------------------------------------- + * 18 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 20 + * | | (PROXY_200) | + *--------------------------------------------------------------------------------------------------------------------------- + * 19 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 20 + * | | (SERVER_100 && PROXY_200) | + *--------------------------------------------------------------------------------------------------------------------------- + * 20 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=-100 | Timeout set to 20 + * | | (SERVER_100_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 21 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.proxy=-200 | Timeout set to 20 + * | | (PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 22 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=-100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Timeout set to 20 + * | | (SERVER_100_NEGATIVE && PROXY_200_NEGATIVE)| + *--------------------------------------------------------------------------------------------------------------------------- + * 23 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=0 | Timeout set to 20 + * | | (SERVER_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 24 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.proxy=0 | Timeout set to 20 + * | | (PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 25 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=0 | Timeout set to 20 + * | | (SERVER_ZERO && PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 26 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Timeout set to 20 + * | | (SERVER_ZERO && PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 27 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=-100 &&| + * | | -Dhttp.keepAlive.time.proxy=0 | Timeout set to 20 + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 28 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | Timeout set to 20 + * | | (SERVER_100 && PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 29 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 20 + * | | (SERVER_ZERO && PROXY_200) | + *--------------------------------------------------------------------------------------------------------------------------- + * 30 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Timeout set to 20 + * | | (SERVER_100 && PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 31 |Connection: keep-alive\r\nKeep-alive: timeout=20 (B) |-Dhttp.keepAlive.time.server=-100 && | + * | |-Dhttp.keepAlive.time.proxy=200 | Timeout set to 20 + * | | (SERVER_100_NEGATIVE && PROXY_200) | + *--------------------------------------------------------------------------------------------------------------------------- + * 32 |Proxy-Connection: keep-alive (C) | No Input Provided (NI) | Default timeout set to 60 + *--------------------------------------------------------------------------------------------------------------------------- + * 33 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.server=100 | Default timeout set to 60 + * | | (SERVER_100) | + *--------------------------------------------------------------------------------------------------------------------------- + * 34 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------- + * 35 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (SERVER_100 && PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------- + * 36 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.server=-100 | Default timeout set to 60 + * | | (SERVER_100_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 37 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.proxy=-200 | Default timeout set to 60 + * | | (PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 38 |Proxy-Connection: keep-alive (C) |-Dhttp.keepAlive.time.server=-100 && | + * | |-Dhttp.keepAlive.time.proxy=-200 | Default timeout set to 60 + * | |(SERVER_100_NEGATIVE && PROXY_200_NEGATIVE)| + *--------------------------------------------------------------------------------------------------------------------------- + * 39 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.server=0 | Default timeout set to 60 + * | | (SERVER_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 40 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 41 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_ZERO && PROXY_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 42 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Default timeout set to 60 + * | | (SERVER_ZERO && PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------------- + * 43 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.server=-100 &&| + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------------- + * 44 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_100 && PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 45 |Proxy-Connection: keep-alive (C) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (SERVER_ZERO && PROXY_200) | + *--------------------------------------------------------------------------------------------------------------------------- + * 46 |Proxy-Connection: keep-alive (C) |-Dhttp.keepAlive.time.server=100 && | + * | |-Dhttp.keepAlive.time.proxy=-200 | Default timeout set to 60 + * | | (SERVER_100 && PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------- + * 47 |Proxy-Connection: keep-alive (C) |-Dhttp.keepAlive.time.server=-100 && | + * | |-Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------- + * 48 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | No Input Provided (NI) | Default timeout set to 60 + *----------------------------------------------------------------------------------------------------------------------------- + * 49 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=100 | Default timeout set to 60 + * | | (SERVER_100) | + *--------------------------------------------------------------------------------------------------------------------------- + * 50 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------ + * 51 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (SERVER_100 && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------ + * 52 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=-100 | Default timeout set to 60 + * | | (SERVER_100_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------ + * 53 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.proxy=-200 | Default timeout set to 60 + * | | (PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------ + * 54 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=-100&& | + * | | -Dhttp.keepAlive.time.proxy=-200 | Default timeout set to 60 + * | | (SERVER_100_NEGATIVE && PROXY_200_NEGATIVE | + *------------------------------------------------------------------------------------------------------------------------------- + * 55 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=0 | Default timeout set to 60 + * | | (SERVER_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 56 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (PROXY_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 57 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_ZERO && PROXY_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 58 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Default timeout set to 60 + * | | (SERVER_ZERO && PROXY_200_NEGATIVE) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 59 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=-100 &&| + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 60 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_100 && PROXY_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 61 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (SERVER_ZERO && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------ + * 62 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | default timeout set to 60 + * | | (SERVER_100 && PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------ + * 63 |Connection:keep-alive\r\nProxy-connection:keep-alive (D) | -Dhttp.keepAlive.time.server=-100 &&| + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (SERVER_100_NEGATIVE && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------- + * 64 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| No Input Provided (NI) | Timeout set to 120 + *------------------------------------------------------------------------------------------------------------------------------- + * 65 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=100 | Timeout set to 120 + * | | (SERVER_100) | + *------------------------------------------------------------------------------------------------------------------------------- + * 66 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.proxy=200 | Timeout set to 120 + * | | (PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------- + * 67 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 120 + * | | (SERVER_100 && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------- + * 68 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=-100 | Timeout set to 120 + * | | (SERVER_100_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------- + * 69 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.proxy=-200 | Timeout set to 120 + * | | (PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------- + * 70 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=-100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Timeout set to 120 + * | | (SERVER_100_NEGATIVE && PROXY_200_NEGATIVE)| + *------------------------------------------------------------------------------------------------------------------------------- + * 71 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=0 | Timeout set to 120 + * | | (SERVER_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------- + * 72 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.proxy=0 | Timeout set to 120 + * | | (PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------- + * 73 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=0 | Timeout set to 120 + * | | (SERVER_ZERO && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------- + * 74 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Timeout set to 120 + * | | (SERVER_ZERO && PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------- + * 75 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=-100 &&| + * | | -Dhttp.keepAlive.time.proxy=0 | Timeout set to 120 + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------- + * 76 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | Timeout set to 120 + * | | (SERVER_100 && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------- + * 77 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 120 + * | | (SERVER_ZERO && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------- + * 78 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | Timeout set to 120 + * | | (SERVER_100_NEGATIVE && PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------- + * 79 |Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 (E)| -Dhttp.keepAlive.time.server=-100 &&| + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 120 + * | | (SERVER_100_NEGATIVE && PROXY_200) | + *----------------------------------------------------------------------------------------------------------------------------- + * 80 |No Input (NI) | No Input Provided (NI) | default timeout set to 5 + *----------------------------------------------------------------------------------------------------------------------------- + * 81 |No Input (NI) | -Dhttp.keepAlive.time.server=100 | Timeout set to 100 + * | | (SERVER_100) | + *----------------------------------------------------------------------------------------------------------------------------- + * 82 |No Input (NI) | -Dhttp.keepAlive.time.proxy=200 | default timeout set to 5 + * | | (PROXY_200) | + *----------------------------------------------------------------------------------------------------------------------------- + * 83 |No Input (NI) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | client timeot set to 100 + * | | (SERVER_100 && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------ + * 84 |No Input (NI) | -Dhttp.keepAlive.time.server=-100 | default timeout set to 5 + * | | (SERVER_100_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------ + * 85 |No Input (NI) | -Dhttp.keepAlive.time.proxy=-200 | default timeout set to 5 + * | | (PROXY_200_NEGATIVE) | + *---------------------------------------------------------------------------------------------------------------------------- + * 86 |No Input (NI) | -Dhttp.keepAlive.time.server=-100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | default timeout set to 5 + * | | (SERVER_100_NEGATIVE && PROXY_200_NEGATIVE)| + *------------------------------------------------------------------------------------------------------------------------------ + * 87 |No Input (NI) | -Dhttp.keepAlive.time.server=0 | close connection immediately + * | | (SERVER_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------------- + * 88 |No Input (NI) | -Dhttp.keepAlive.time.proxy=0 | default timeout set to 5 + * | | (PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------------- + * 89 |No Input (NI) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_ZERO && PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------------- + * 90 |No Input (NI) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | close connection immediately + * | | (SERVER_ZERO && PROXY_200_NEGATIVE) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 91 |No Input (NI) | -Dhttp.keepAlive.time.server=-100 &&| + * | | -Dhttp.keepAlive.time.proxy=0 | default timeout set to 5 + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 92 |No Input (NI) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | Timeout set to 100 + * | | (SERVER_100 && PROXY_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 93 |No Input (NI) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=200 | close connection immediately + * | | (SERVER_ZERO && PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 94 |No Input (NI) |-Dhttp.keepAlive.time.server=100 && | + * | |-Dhttp.keepAlive.time.proxy=-200 | Timeout set to 100 + * | | (SERVER_100 && PROXY_200_NEGATIVE) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 95 |No Input (NI) |-Dhttp.keepAlive.time.server=-100 && | + * | |-Dhttp.keepAlive.time.proxy=200 | default timeout set to 5 + * | | (SERVER_100_NEGATIVE && PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 96 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) | No Input Provided (NI) | default timeout set to 5 + *-------------------------------------------------------------------------------------------------------------------------------- + * 97 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=100 | Timeout set to 100 + * | | (SERVER_100) | + *-------------------------------------------------------------------------------------------------------------------------------- + * 98 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.proxy=200 | default timeout set to 5 + * | | (PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 99 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=100 && | + * | |-Dhttp.keepAlive.time.proxy=200 | Timeout set to 100 + * | |(SERVER_100 && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 100 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=-100 | default timeout set to 5 + * | |(SERVER_100_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 101 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.proxy=-200 | default timeout set to 5 + * | |(PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 102 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=-100 && | + * | |-Dhttp.keepAlive.time.proxy=-200 | default timeout set to 5 + * | | (SERVER_100_NEGATIVE && PROXY_200_NEGATIVE)| + *------------------------------------------------------------------------------------------------------------------------------------- + * 103 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=0 | close connection immediately + * | | (SERVER_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 104 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.proxy=0 | default timeout set to 5 + * | | (PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 105 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_ZERO && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 106 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=0 && | + * | |-Dhttp.keepAlive.time.proxy=-200 | close connection immediately + * | | (SERVER_ZERO && PROXY_ZERO_NEGATIVE)| + *------------------------------------------------------------------------------------------------------------------------------------- + * 107 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=-100 && | + * | |-Dhttp.keepAlive.time.proxy=0 | default timeout set to 5 + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 108 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=100 && | + * | |-Dhttp.keepAlive.time.proxy=0 | Timeout set to 100 + * | | (SERVER_100 && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 109 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=0 && | + * | |-Dhttp.keepAlive.time.proxy=200 | close connection immediately + * | | (SERVER_ZERO && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 110 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=100 && | + * | |-Dhttp.keepAlive.time.proxy=-200 | Timeout set to 100 + * | |(SERVER_100 && PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 111 |Connection: keep-alive\r\nKeep-alive: timeout=-20 (F) |-Dhttp.keepAlive.time.server=-100 && | + * | |-Dhttp.keepAlive.time.proxy=200 | default timeout set to 5 + * | | (SERVER_100_NEGATIVE && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 112 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | No Input Provided (NI) | close connection immediately + *------------------------------------------------------------------------------------------------------------------------------------- + * 113 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=100 | close connection immediately + * | | (SERVER_100) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 114 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.proxy=200 | close connection immediately + * | | (PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 115 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | close connection immediately + * | | (SERVER_100 && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 116 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=-100 | close connection immediately + * | | (SERVER_100_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------ + * 117 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.proxy=-200 | close connection immediately + * | | (PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 118 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) |-Dhttp.keepAlive.time.server=-100 && | + * | |-Dhttp.keepAlive.time.proxy=-200 | close connection immediately + * | | (SERVER_100_NEGATIVE && PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 119 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=0 | close connection immediately + * | | (SERVER_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 120 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------ + * 121 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_ZERO && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 122 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | close connection immediately + * | | (SERVER_ZERO && PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 123 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=-100 &&| + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 124 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_100 && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 125 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=200 | close connection immediately + * | | (SERVER_ZERO && PROXY_200) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 126 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | close connection immediately + * | | (SERVER_100 && PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 127 |Connection: keep-alive\r\nKeep-alive: timeout=0 (G) | -Dhttp.keepAlive.time.server=-100 &&| + * | | -Dhttp.keepAlive.time.proxy=200 | close connection immediately + * | | (SERVER_100_NEGATIVE && PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 128 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| No Input Provided (NI) | default timeout set to 60 + --------------------------------------------------------------------------------------------------------------------------------------- + * 129 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.server=100 | default timeout set to 60 + * | | (SERVER_100) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 130 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 131 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (SERVER_100 && PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 132 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.server=-100 | default timeout set to 60 + * | | (SERVER_100_NEGATIVE) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 133 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.proxy=-200 | default timeout set to 60 + * | | (PROXY_200_NEGATIVE) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 134 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)|-Dhttp.keepAlive.time.server=-100 && | + * | |-Dhttp.keepAlive.time.proxy=-200 | default timeout set to 60 + * | | (SERVER_100_NEGATIVE && PROXY_200_NEGATIVE)| + *--------------------------------------------------------------------------------------------------------------------------------- + * 135 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.server=0 | default timeout set to 60 + * | | (SERVER_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 136 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (PROXY_ZERO) | + *---------------------------------------------------------------------------------------------------------------------------------- + * 137 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_ZERO && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 138 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | default timeout set to 60 + * | | (SERVER_ZERO && PROXY_200_NEGATIVE) | + *--------------------------------------------------------------------------------------------------------------------------------------- + * 139 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.server=-100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 140 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_100 && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 141 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)| -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=200 | Timeout set to 20 + * | | (SERVER_ZERO && PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 142 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)|-Dhttp.keepAlive.time.server=100 && | + * | |-Dhttp.keepAlive.time.proxy=-200 | default timeout set to 60 + * | | (SERVER_100 && PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 143 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=-20 (H)|-Dhttp.keepAlive.time.server=-100 && | + * | |-Dhttp.keepAlive.time.proxy=200 | Timeout set to 200 + * | | (SERVER_100_NEGATIVE && PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 144 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | No Input Provided (NI) | close connection immediately + *-------------------------------------------------------------------------------------------------------------------------------------- + * 145 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=100 | close connection immediately + * | | (SERVER_100) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 146 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.proxy=200 | close connection immediately + * | | (PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 147 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | close connection immediately + * | | (SERVER_100 && PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 148 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=-100 | close connection immediately + * | | (SERVER_100_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 149 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.proxy=-200 | close connection immediately + * | | (PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 150 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=-100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | close connection immediately + * | | (SERVER_100_NEGATIVE && PROXY_200_NEGATIVE) | + *------------------------------------------------------------------------------------------------------------------------------------ + * 151 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=0 | close connection immediately + * | | (SERVER_ZERO) | + *----------------------------------------------------------------------------------------------------------------------------------- + * 152 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (PROXY_ZERO) | + *--------------------------------------------------------------------------------------------------------------------------------- + * 153 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_ZERO && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------ + * 154 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | close connection immediately + * | | (SERVER_ZERO && PROXY_200_NEGATIVE) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 155 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=-100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_100_NEGATIVE && PROXY_ZERO) | + *------------------------------------------------------------------------------------------------------------------------------------- + * 156 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=0 | close connection immediately + * | | (SERVER_100 && PROXY_ZERO) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 157 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=0 && | + * | | -Dhttp.keepAlive.time.proxy=200 | close connection immediately + * | | (SERVER_ZERO && PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 158 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=100 && | + * | | -Dhttp.keepAlive.time.proxy=-200 | close connection immediately + * | | (SERVER_100 && PROXY_200_NEGATIVE) | + *-------------------------------------------------------------------------------------------------------------------------------------- + * 159 |Proxy-Connection:keep-alive\r\nKeep-alive:timeout=0 (I) | -Dhttp.keepAlive.time.server=-100 && | + * | | -Dhttp.keepAlive.time.proxy=200 | close connection immediately + * | | (SERVER_100_NEGATIVE && PROXY_200) | + *-------------------------------------------------------------------------------------------------------------------------------------- + */ + + /* private static final String[] serverScenarios = { + A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, A, + B, B, B, B, B, B, B, B, B, B,B, B, B, B, B, B, + C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, C, + D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, D, + E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, E, + NI, NI, NI, NI, NI, NI, NI, NI, NI, NI, NI, NI, NI, NI, NI, NI, + F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, F, + G, G, G, G, G, G, G, G, G, G, G, G, G, G, G, G, + H, H, H, H, H, H, H, H, H, H, H, H, H, H, H, H, + I, I, I, I, I, I, I, I, I, I, I, I, I, I, I, I + }; */ + /* + * following are client scenarios which are repeated. + */ + private static final String[] a = { + NI, SERVER_100, PROXY_200, SERVER_100 + CLIENT_SEPARATOR + PROXY_200, SERVER_100_NEGATIVE, + PROXY_200_NEGATIVE, SERVER_100_NEGATIVE + CLIENT_SEPARATOR + PROXY_200_NEGATIVE, + SERVER_ZERO, PROXY_ZERO, SERVER_ZERO + CLIENT_SEPARATOR + PROXY_ZERO, + SERVER_ZERO + CLIENT_SEPARATOR + PROXY_200_NEGATIVE, SERVER_100_NEGATIVE + CLIENT_SEPARATOR + PROXY_ZERO, + SERVER_100 + CLIENT_SEPARATOR + PROXY_ZERO, SERVER_ZERO + CLIENT_SEPARATOR + PROXY_200, + SERVER_100 + CLIENT_SEPARATOR + PROXY_200_NEGATIVE, SERVER_100_NEGATIVE + CLIENT_SEPARATOR + PROXY_200 + }; + + /* private String[] clientScenarios = { + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15], + }; */ + + private static final String[] clientScenarios = { + a[0] , a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11], a[12], a[13], a[14], a[15] + }; + + private static final int[] expectedValues = { + 5, 100, 5, 100, 5, 5, 5, 0, 5, 0, 0, 5, 100, 0, 100, 5, + 20, 20 , 20, 20, 20, 20, 20, 20, 20, 20 , 20, 20, 20, 20, 20, 20, + 60, 60, 200, 200, 60, 60, 60, 60, 0, 0, 60, 0, 0, 200, 60, 200, + 60, 60, 200, 200, 60, 60, 60, 60, 0, 0, 60, 0, 0, 200, 60, 200, + 120, 120, 120, 120,120,120,120,120,120, 120, 120, 120, 120, 120, 120, 120, + 5, 100, 5, 100, 5, 5, 5, 0, 5, 0, 0, 5, 100, 0, 100, 5, + 5, 100, 5, 100, 5, 5, 5, 0, 5, 0, 0, 5, 100, 0, 100, 5, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 60, 60, 200, 200, 60, 60, 60, 60, 0, 0, 60, 0, 0, 200, 60, 200, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + private final CountDownLatch countDownLatch = new CountDownLatch(1); + + private final CountDownLatch serverCountDownLatch = new CountDownLatch(1); + + /* + * setting of client properties -Dhttp.keepAlive.time.server and -Dhttp.keepAlive.time.proxy is handled through this method. + * There are 16 client scenarios in total starting with scenarioNumber 0(zero) and ending with 15. + * Server Scenarios are grouped into batch of 16 scenarios. + * There are 10 batches in total and each batch contains 16 scenarios so 10 * 16 = 160 scenarios in total. + * 16 Client Scenarios are used repeatedly for every server scenario batch. + * for serverscenario[0],serverscenario[16],serverscenario[32] ... serverscenario[144] is mapped to clientscenario[0] + * for serverscenario[1],serverscenario[17],serverscenario[33] ... serverscenario[145] is mapped to clientscenario[1] + * for serverscenario[2],serverscenario[18],serverscenario[34] ... serverscenario[146] is mapped to clientscenario[2] + * ... + * for serverscenario[15],serverscenario[31],serverscenario[47] ... serverscenario[159] is mapped to clientscenario[15] + */ + private int getClientScenarioNumber(int scenarioNumber) { + return scenarioNumber % 16 ; + } + + /* + * Returns SERVER_RESPONSE as String based on integer inputParameter scenarioNumber. + * Server Scenarios are grouped into batch of 16 scenarios starting with scenarioNumber 0 (zero) + * so there are 10 batches in total and each batch contains 16 scenarios so 10 * 16 = 160 scenarios in total. + * For each batch of 16 scenarios, there will be common SERVER_RESPONSE for all 16 scenarios in batch. + * for scenario numbers from 0 to 15 server response is: Connection:keep-alive + * for scenario numbers from 16 to 31 server response is: SERVER_RESPONSE=Connection: keep-alive\r\nKeep-alive: timeout=20 + * for scenario numbers from 32 to 47 server response is: SERVER_RESPONSE=Proxy-Connection: keep-alive + * for scenario numbers from 48 to 63 server response is: SERVER_RESPONSE=Connection:keep-alive\r\nProxy-connection:keep-alive + * for scenario numbers from 64 to 79 server response is: SERVER_RESPONSE=Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 + * for scenario numbers from 80 to 95 server response is: SERVER_RESPONSE=No Input + * for scenario numbers from 96 to 111 server response is: SERVER_RESPONSE=Connection: keep-alive\r\nKeep-alive: timeout=-20 + * for scenario numbers from 112 to 127 server resonse is: Connection: keep-alive\r\nKeep-alive: timeout=0 + * for scenario numbers from 128 to 143 server response is: Proxy-connection:keep-alive\r\nKeep-alive:timeout=-20 + * for scenario numbers from 144 to 159 server response is: Proxy-connection:keep-alive\r\nKeep-alive:timeout=0 + */ + private String getServerScenario(int scenarioNumber) { + /* + * ServerResponse for scenarios from 0 to 15 + * SERVER_RESPONSE:Connection:keep-alive + */ + if(scenarioNumber >= 0 && scenarioNumber <= 15) { + return A; + } + /* + * ServerResponse for scenarios from 16 to 31 + * SERVER_RESPONSE=Connection: keep-alive\r\nKeep-alive: timeout=20 + */ + else if (scenarioNumber >= 16 && scenarioNumber <= 31){ + return B; + } + /* + * ServerResponse for scenarios from 32 to 47 + * SERVER_RESPONSE=Proxy-Connection: keep-alive + */ + else if (scenarioNumber >= 32 && scenarioNumber <= 47){ + return C; + } + /* + * ServerResponse for scenarios from 48 to 63 + * SERVER_RESPONSE=Connection:keep-alive\r\nProxy-connection:keep-alive + */ + else if (scenarioNumber >= 48 && scenarioNumber <= 63){ + return D; + /* + * ServerResponse for scenarios from 64 to 79 + * SERVER_RESPONSE=Proxy-connection:keep-alive\r\nKeep-alive:timeout=120 + */ + } else if (scenarioNumber >= 64 && scenarioNumber <= 79){ + return E; + } + /* + * ServerResponse for scenarios from 80 to 95 + * SERVER_RESPONSE=No Input + */ + else if (scenarioNumber >= 80 && scenarioNumber <= 95){ + return NI; + } + /* + * ServerResponse for scenarios from 96 to 111 + * SERVER_RESPONSE=Connection: keep-alive\r\nKeep-alive: timeout=-20 + */ + else if (scenarioNumber >= 96 && scenarioNumber <= 111){ + return F; + } + /* + * ServerResponse for scenarios from 112 to 127 + * SERVER_RESPONSE=Connection: keep-alive\r\nKeep-alive: timeout=0 + */ + else if (scenarioNumber >= 112 && scenarioNumber <= 127){ + return G; + } + /* + * ServerResponse for scenarios from 128 to 143 + * SERVER_RESPONSE=Proxy-connection:keep-alive\r\nKeep-alive:timeout=-20 + */ + else if (scenarioNumber >= 128 && scenarioNumber <= 143){ + return H; + } + /* + * ServerResponse for scenarios from 144 to 159 + * SERVER_RESPONSE=Proxy-connection:keep-alive\r\nKeep-alive:timeout=0 + */ + else if (scenarioNumber >= 144 && scenarioNumber <= 159){ + return I; + } + /*Invalid Case*/ + return null; + } + + private void startScenario(int scenarioNumber) throws Exception { + //test scenarios are skipped because of JDK-8291638 + if((scenarioNumber >= 112 && scenarioNumber <= 127) || (scenarioNumber >= 144 && scenarioNumber <= 159)) { + System.out.println("Scenario Skipped:"+scenarioNumber); + this.countDownLatch.countDown(); + return; + } + System.out.println("serverScenarios[" + scenarioNumber + "]=" + getServerScenario(scenarioNumber)); + System.out.println("clientScenarios[" + scenarioNumber + "]=" + clientScenarios[getClientScenarioNumber(scenarioNumber)]); + if(expectedValues[scenarioNumber] == 0) { + System.out.println("ExpectedOutput=" + NOT_CACHED); + } else { + System.out.println("ExpectedOutput=" + expectedValues[scenarioNumber]); + } + System.out.println(); + startServer(scenarioNumber); + runClient(scenarioNumber); + } + + private void startServer(int scenarioNumber) { + Thread server = new Thread(new Runnable() { + @Override + public void run() { + try { + executeServer(scenarioNumber); + } catch (IOException e) { + e.printStackTrace(); + } + } + }, "SERVER"); + server.start(); + } + + private void readAll(Socket s) throws IOException { + byte[] buf = new byte[128]; + int c; + String request = ""; + InputStream is = s.getInputStream(); + while ((c = is.read(buf)) > 0) { + request += new String(buf, 0, c, StandardCharsets.US_ASCII); + if (request.contains("\r\n\r\n")) { + return; + } + } + if (c == -1) { + throw new IOException("Socket closed"); + } + } + + private void executeServer(int scenarioNumber) throws IOException { + String serverScenarioContent = null; + if (!getServerScenario(scenarioNumber).equalsIgnoreCase(NI)) { + serverScenarioContent = getServerScenario(scenarioNumber) + NEW_LINE; + /* + * isProxySet should be set before Server is moved to Listen State. + */ + if (serverScenarioContent.contains("Proxy")) { + isProxySet = true; + } else { + isProxySet = false; + } + } + ServerSocket serverSocket = null; + Socket socket = null; + OutputStreamWriter out = null; + InetAddress loopback = InetAddress.getLoopbackAddress(); + try { + serverSocket = new ServerSocket(); + serverSocket.bind(new InetSocketAddress(loopback, 0)); + SERVER_PORT = serverSocket.getLocalPort(); + //serverReady = true; + this.serverCountDownLatch.countDown(); + System.out + .println("SERVER_PORT= " + SERVER_PORT +" isProxySet=" + isProxySet); + /* + * Server will be waiting for clients to connect. + */ + socket = serverSocket.accept(); + readAll(socket); + out = new OutputStreamWriter(socket.getOutputStream()); + String BODY = "SERVER REPLY: Hello world"; + String CLEN = "Content-Length: " + BODY.length() + NEW_LINE; + /* send the header */ + out.write("HTTP/1.1 200 OK\r\n"); + out.write("Content-Type: text/plain; charset=iso-8859-1\r\n"); + /* + * append each scenario content from array. + */ + if(serverScenarioContent != null) { + out.write(serverScenarioContent); + } + out.write(CLEN); + out.write(NEW_LINE); + out.write(BODY); + out.flush(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if (out != null) { + out.flush(); + out.close(); + } + if (socket != null) { + socket.close(); + } + if (serverSocket != null) { + serverSocket.close(); + } + } + } + + private void runClient(int scenarioNumber) throws Exception { + try { + connectToServerURL(scenarioNumber); + } finally { + System.out.println("client count down latch:" + scenarioNumber); + this.countDownLatch.countDown(); + System.out.println(); + System.out.println(); + } + } + + private void connectToServerURL(int scenarioNumber) throws Exception { + // System.setProperty("java.net.useSystemProxies", "false"); + // System.setProperty("http.nonProxyHosts", ""); + // System.setProperty("http.proxyHost", "localhost"); + // System.setProperty("http.proxyPort", String.valueOf(SERVER_PORT)); + System.out.println("Following are Existing System Properties if set any"); + System.out.println("http.keepAlive.time.server:" + System.getProperty("http.keepAlive.time.server")); + System.out.println("http.keepAlive.time.proxy:" + System.getProperty("http.keepAlive.time.proxy")); + System.setProperty("java.net.useSystemProxies", "false"); + System.out.println("http.proxyPort:"+System.getProperty("http.proxyPort")); + System.out.println("http.proxyHost:"+System.getProperty("http.proxyHost")); + System.clearProperty("http.keepAlive.time.server"); + System.clearProperty("http.keepAlive.time.proxy"); + // fetch clientScenearios for each scenarioNumber from array and set it to + // System property. + if (!clientScenarios[getClientScenarioNumber(scenarioNumber)].equalsIgnoreCase(NI)) { + System.out.println("Client Input Parsing"); + for (String clientScenarioString : clientScenarios[getClientScenarioNumber(scenarioNumber)].split(CLIENT_SEPARATOR)) { + System.out.println(clientScenarioString); + String key = clientScenarioString.split("=")[0]; + String value = clientScenarioString.split("=")[1]; + System.setProperty(key, value); + } + } + // wait until ServerSocket moves to listening state. + this.serverCountDownLatch.await(); + System.out.println("client started"); + URL url = URIBuilder.newBuilder().scheme("http").loopback().port(SERVER_PORT).toURL(); + System.out.println("connecting from client to SERVER URL:" + url); + HttpURLConnection httpUrlConnection = null; + /* + * isProxySet is set to true when Expected Server Response contains Proxy-Connection header. + */ + if (isProxySet) { + httpUrlConnection = (sun.net.www.protocol.http.HttpURLConnection) url + .openConnection(new Proxy(Type.HTTP, new InetSocketAddress("localhost", SERVER_PORT))); + } else { + httpUrlConnection = (sun.net.www.protocol.http.HttpURLConnection) url.openConnection(); + } + InputStreamReader inputStreamReader = new InputStreamReader(httpUrlConnection.getInputStream()); + BufferedReader bufferedReader = null; + try { + bufferedReader = new BufferedReader(inputStreamReader); + while (true) { + String eachLine = bufferedReader.readLine(); + if (eachLine == null) { + break; + } + System.out.println(eachLine); + } + } finally { + if (bufferedReader != null) { + bufferedReader.close(); + } + } + // System.out.println("ResponseCode:" + httpUrlConnection.getResponseCode()); + // System.out.println("ResponseMessage:" + httpUrlConnection.getResponseMessage()); + // System.out.println("Content:" + httpUrlConnection.getContent()); + // Thread.sleep(2000); + for (Entry> header : httpUrlConnection.getHeaderFields().entrySet()) { + System.out.println(header.getKey() + "=" + header.getValue()); + } + fetchInfo(scenarioNumber, httpUrlConnection); + } + + private void fetchInfo(int scenarioNumber, sun.net.www.protocol.http.HttpURLConnection httpUrlConnection) + throws Exception { + Field field = Class.forName("sun.net.www.protocol.http.HttpURLConnection").getDeclaredField("http"); + field.setAccessible(true); + HttpClient httpClient = (HttpClient) field.get(httpUrlConnection); + // System.out.println("httpclient=" + httpClient); + Field keepAliveField = Class.forName("sun.net.www.http.HttpClient").getDeclaredField("kac"); + keepAliveField.setAccessible(true); + KeepAliveCache keepAliveCache = (KeepAliveCache) keepAliveField.get(httpClient); + System.out.println("keepAliveCache" + keepAliveCache); + System.out.println("SERVER URL:" + httpUrlConnection.getURL()); + /* + * create KeepAliveKey(URL,Object) object and compare created KeepAliveKey and + * existing using equals() method: KeepAliveKey.equals() + */ + Class keepAliveKeyClass = Class.forName("sun.net.www.http.KeepAliveKey"); + // System.out.println("keepAliveKeyClass=" + keepAliveKeyClass); + Constructor keepAliveKeyClassconstructor = keepAliveKeyClass.getDeclaredConstructors()[0]; + keepAliveKeyClassconstructor.setAccessible(true); + Object expectedKeepAliveKey = keepAliveKeyClassconstructor.newInstance(httpUrlConnection.getURL(), null); + System.out.println("ExpectedKeepAliveKey=" + expectedKeepAliveKey); + Object clientVectorObjectInMap = keepAliveCache.get(expectedKeepAliveKey); + System.out.println("ClientVector=" + clientVectorObjectInMap); + HttpClient httpClientCached = keepAliveCache.get(httpUrlConnection.getURL(), null); + System.out.println("HttpClient in Cache:" + httpClientCached); + if(httpClientCached != null) { + System.out.println("KeepingAlive:" + httpClientCached.isKeepingAlive()); + System.out.println("UsingProxy:" + httpClientCached.getUsingProxy()); + System.out.println("ProxiedHost:" + httpClientCached.getProxyHostUsed()); + System.out.println("ProxiedPort:" + httpClientCached.getProxyPortUsed()); + System.out.println("ProxyPortUsingSystemProperty:" + System.getProperty("http.proxyPort")); + System.out.println("ProxyHostUsingSystemProperty:" + System.getProperty("http.proxyHost")); + System.out.println("http.keepAlive.time.server=" + System.getProperty("http.keepAlive.time.server")); + System.out.println("http.keepAlive.time.proxy=" + System.getProperty("http.keepAlive.time.proxy")); + Class clientVectorClass = Class.forName("sun.net.www.http.ClientVector"); + // System.out.println("clientVectorClass=" + clientVectorClass); + Field napField = clientVectorClass.getDeclaredField("nap"); + napField.setAccessible(true); + int napValue = (int) napField.get(clientVectorObjectInMap); + int actualValue = napValue / 1000; + // System.out.println("nap=" + napValue / 1000); + System.out.printf("ExpectedOutput:%d ActualOutput:%d ", expectedValues[scenarioNumber], actualValue); + System.out.println(); + if (expectedValues[scenarioNumber] != actualValue) { + throw new RuntimeException( + "ExpectedOutput:" + expectedValues[scenarioNumber] + " ActualOutput: " + actualValue); + } + } else { + //executed when value is not cached. + String expected = expectedValues[scenarioNumber] == 0 ? NOT_CACHED + : String.valueOf(expectedValues[scenarioNumber]); + System.out.println("ExpectedOutput:" + expected + " ActualOutput:" + NOT_CACHED); + if (!expected.equalsIgnoreCase(NOT_CACHED)) { + throw new RuntimeException("ExpectedOutput:" + expected + " ActualOutput:" + NOT_CACHED); + } + } + } + + public static void main(String[] args) throws Exception { + if (args.length != 1) { + throw new IllegalArgumentException("Usage:java KeepAliveTest.java "); + } + logger.setLevel(Level.FINEST); + ConsoleHandler h = new ConsoleHandler(); + h.setLevel(Level.FINEST); + logger.addHandler(h); + KeepAliveTest keepAliveTest = new KeepAliveTest(); + if (args.length != 0) { + keepAliveTest.startScenario(Integer.valueOf(args[0])); + } + // make main thread wait until server and client is completed. + keepAliveTest.countDownLatch.await(); + } +} From 8bc5ad105a3da4e165dfabdd512d7d52236b7377 Mon Sep 17 00:00:00 2001 From: Matthias Baesken Date: Thu, 30 Mar 2023 12:06:17 +0000 Subject: [PATCH 026/217] 8304671: javac regression: Compilation with --release 8 fails on underscore in enum identifiers Reviewed-by: phh Backport-of: 63d4afbeb17df4eff0f65041926373ee62a8a33a --- .../sun/tools/javac/parser/JavacParser.java | 16 +- .../tools/javac/parser/JavacParserTest.java | 169 +++++++++++++++++- 2 files changed, 176 insertions(+), 9 deletions(-) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index 75559bb9872..cd1a32b254b 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -4120,10 +4120,13 @@ List enumBody(Name enumName) { return defs.toList(); } + @SuppressWarnings("fallthrough") private EnumeratorEstimate estimateEnumeratorOrMember(Name enumName) { // if we are seeing a record declaration inside of an enum we want the same error message as expected for a // let's say an interface declaration inside an enum - if (token.kind == TokenKind.IDENTIFIER && token.name() != enumName && + boolean ident = token.kind == TokenKind.IDENTIFIER || + token.kind == TokenKind.UNDERSCORE; + if (ident && token.name() != enumName && (!allowRecords || !isRecordStart())) { Token next = S.token(1); switch (next.kind) { @@ -4132,12 +4135,11 @@ private EnumeratorEstimate estimateEnumeratorOrMember(Name enumName) { } } switch (token.kind) { - case IDENTIFIER: case MONKEYS_AT: case LT: - if (token.kind == IDENTIFIER) { - if (allowRecords && isRecordStart()) { - return EnumeratorEstimate.MEMBER; - } + case IDENTIFIER: + if (allowRecords && isRecordStart()) { + return EnumeratorEstimate.MEMBER; } + case MONKEYS_AT: case LT: case UNDERSCORE: return EnumeratorEstimate.UNKNOWN; default: return EnumeratorEstimate.MEMBER; diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index 6dad41a1e73..2be34677393 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 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 @@ -23,7 +23,7 @@ /* * @test - * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 + * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8304671 * @summary tests error and diagnostics positions * @author Jan Lahoda * @modules jdk.compiler/com.sun.tools.javac.api @@ -1795,6 +1795,171 @@ private void test(int[]... p) {} assertEquals("correct parameter type span", code.substring(typeStart, typeEnd), "int[]..."); } + @Test //JDK-8304671 + void testEnumConstantUnderscore() throws IOException { + record TestCase(String code, String release, String ast, String errors) {} + TestCase[] testCases = new TestCase[] { + new TestCase(""" + package t; + enum Test { + _ + } + """, + "8", + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + } """, + """ + Test.java:3:5: compiler.warn.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + _ + } + """, + System.getProperty("java.specification.version"), + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + } """, + """ + Test.java:3:5: compiler.err.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + _; + } + """, + "8", + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + } """, + """ + Test.java:3:5: compiler.warn.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + _; + } + """, + System.getProperty("java.specification.version"), + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + } """, + """ + Test.java:3:5: compiler.err.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + A; + void t() {} + _; + } + """, + "8", + """ + package t; + \n\ + enum Test { + /*public static final*/ A /* = new Test() */ /*enum*/ , + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + \n\ + void t() { + } + } """, + """ + Test.java:5:5: compiler.err.enum.constant.not.expected + Test.java:5:5: compiler.warn.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + A; + void t() {} + _; + } + """, + System.getProperty("java.specification.version"), + """ + package t; + \n\ + enum Test { + /*public static final*/ A /* = new Test() */ /*enum*/ , + /*public static final*/ _ /* = new Test() */ /*enum*/ ; + \n\ + void t() { + } + } """, + """ + Test.java:5:5: compiler.err.enum.constant.not.expected + """), + new TestCase(""" + package t; + enum Test { + _ {}, + A; + } + """, + "8", + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ { + }, + /*public static final*/ A /* = new Test() */ /*enum*/ ; + } """, + """ + Test.java:3:5: compiler.warn.underscore.as.identifier + """), + new TestCase(""" + package t; + enum Test { + _ {}, + A; + } + """, + System.getProperty("java.specification.version"), + """ + package t; + \n\ + enum Test { + /*public static final*/ _ /* = new Test() */ /*enum*/ { + }, + /*public static final*/ A /* = new Test() */ /*enum*/ ; + } """, + """ + Test.java:3:5: compiler.err.underscore.as.identifier + """), + }; + for (TestCase testCase : testCases) { + StringWriter out = new StringWriter(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(out, fm, null, + List.of("-XDrawDiagnostics", "--release", testCase.release), + null, Arrays.asList(new MyFileObject(testCase.code))); + String ast = ct.parse().iterator().next().toString().replaceAll("\\R", "\n"); + assertEquals("Unexpected AST, got:\n" + ast, testCase.ast, ast); + assertEquals("Unexpected errors, got:\n" + out.toString(), + out.toString().replaceAll("\\R", "\n"), + testCase.errors); + } + } + void run(String[] args) throws Exception { int passed = 0, failed = 0; final Pattern p = (args != null && args.length > 0) From 590256ddcb1bdda10131bdba2c70b919594785c0 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Fri, 31 Mar 2023 11:00:47 +0000 Subject: [PATCH 027/217] 8275721: Name of UTC timezone in a locale changes depending on previous code Backport-of: 543d1a8cf41d32dca161c9d8041f133a71bf0ecb --- .../cldr/CLDRTimeZoneNameProviderImpl.java | 42 +++++------ .../TimeZone/ChineseTimeZoneNameTest.java | 72 +++++++++++++++++++ 2 files changed, 91 insertions(+), 23 deletions(-) create mode 100644 test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java index 6d78d77f64d..d03e753a0a4 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java @@ -82,7 +82,7 @@ protected String[] getDisplayNameArray(String id, Locale locale) { } if (namesSuper != null) { - // CLDR's resource bundle has an translated entry for this id. + // CLDR's resource bundle has a translated entry for this id. // Fix up names if needed, either missing or no-inheritance namesSuper[INDEX_TZID] = id; @@ -91,7 +91,7 @@ protected String[] getDisplayNameArray(String id, Locale locale) { case "": // Fill in empty elements deriveFallbackName(namesSuper, i, locale, - !TimeZone.getTimeZone(id).useDaylightTime()); + TimeZone.getTimeZone(id).toZoneId().getRules().isFixedOffset()); break; case NO_INHERITANCE_MARKER: // CLDR's "no inheritance marker" @@ -129,7 +129,7 @@ protected String[][] getZoneStrings(Locale locale) { // Derive fallback time zone name according to LDML's logic private void deriveFallbackNames(String[] names, Locale locale) { - boolean noDST = !TimeZone.getTimeZone(names[0]).useDaylightTime(); + boolean noDST = TimeZone.getTimeZone(names[0]).toZoneId().getRules().isFixedOffset(); for (int i = INDEX_STD_LONG; i <= INDEX_GEN_SHORT; i++) { deriveFallbackName(names, i, locale, noDST); @@ -149,13 +149,12 @@ private void deriveFallbackName(String[] names, int index, Locale locale, boolea return; } - // Check parent locale first + // Check parent locales first if (!exists(names, index)) { CLDRLocaleProviderAdapter clpa = (CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR); var cands = clpa.getCandidateLocales("", locale); - if (cands.size() > 1) { - var parentLoc = cands.get(1); // immediate parent locale - String[] parentNames = super.getDisplayNameArray(id, parentLoc); + for (int i = 1; i < cands.size() ; i++) { + String[] parentNames = super.getDisplayNameArray(id, cands.get(i)); if (parentNames != null && !parentNames[index].isEmpty()) { names[index] = parentNames[index]; return; @@ -163,22 +162,6 @@ private void deriveFallbackName(String[] names, int index, Locale locale, boolea } } - // Check if COMPAT can substitute the name - if (LocaleProviderAdapter.getAdapterPreference().contains(Type.JRE)) { - String[] compatNames = (String[])LocaleProviderAdapter.forJRE() - .getLocaleResources(mapChineseLocale(locale)) - .getTimeZoneNames(id); - if (compatNames != null) { - for (int i = INDEX_STD_LONG; i <= INDEX_GEN_SHORT; i++) { - // Assumes COMPAT has no empty slots - if (i == index || !exists(names, i)) { - names[i] = compatNames[i]; - } - } - return; - } - } - // Region Fallback if (regionFormatFallback(names, index, locale)) { return; @@ -189,6 +172,19 @@ private void deriveFallbackName(String[] names, int index, Locale locale, boolea return; } + // Check if COMPAT can substitute the name + if (!exists(names, index) && + LocaleProviderAdapter.getAdapterPreference().contains(Type.JRE)) { + String[] compatNames = (String[])LocaleProviderAdapter.forJRE() + .getLocaleResources(mapChineseLocale(locale)) + .getTimeZoneNames(id); + if (compatNames != null) { + // Assumes COMPAT has no empty slots + names[index] = compatNames[index]; + return; + } + } + // last resort names[index] = toGMTFormat(id, index == INDEX_DST_LONG || index == INDEX_DST_SHORT, diff --git a/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java b/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java new file mode 100644 index 00000000000..c752ec4d63c --- /dev/null +++ b/test/jdk/sun/util/resources/TimeZone/ChineseTimeZoneNameTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021, 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. + */ + + /* + * @test + * @bug 8275721 + * @modules jdk.localedata + * @summary Checks Chinese time zone names for `UTC` using CLDR are consistent + * @run testng/othervm -Djava.locale.providers=CLDR,COMPAT ChineseTimeZoneNameTest + * @run testng/othervm -Djava.locale.providers=CLDR ChineseTimeZoneNameTest + */ + +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Locale; + +import static org.testng.Assert.assertEquals; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; + +@Test +public class ChineseTimeZoneNameTest { + + private static final Locale SIMPLIFIED_CHINESE = Locale.forLanguageTag("zh-Hans"); + private static final Locale TRADITIONAL_CHINESE = Locale.forLanguageTag("zh-Hant"); + private static final ZonedDateTime EPOCH_UTC = + ZonedDateTime.ofInstant(Instant.ofEpochSecond (0), ZoneId.of ("UTC")); + + @DataProvider(name="locales") + Object[][] data() { + return new Object[][] { + {Locale.CHINESE, SIMPLIFIED_CHINESE}, + {Locale.SIMPLIFIED_CHINESE, SIMPLIFIED_CHINESE}, + {Locale.forLanguageTag("zh-SG"), SIMPLIFIED_CHINESE}, + {Locale.forLanguageTag("zh-Hans-TW"), SIMPLIFIED_CHINESE}, + {Locale.forLanguageTag("zh-HK"), TRADITIONAL_CHINESE}, + {Locale.forLanguageTag("zh-MO"), TRADITIONAL_CHINESE}, + {Locale.TRADITIONAL_CHINESE, TRADITIONAL_CHINESE}, + {Locale.forLanguageTag("zh-Hant-CN"), TRADITIONAL_CHINESE}, + }; + } + + @Test(dataProvider="locales") + public void test_ChineseTimeZoneNames(Locale testLoc, Locale resourceLoc) { + assertEquals(DateTimeFormatter.ofPattern("z", testLoc).format(EPOCH_UTC), + DateTimeFormatter.ofPattern("z", resourceLoc).format(EPOCH_UTC)); + assertEquals(DateTimeFormatter.ofPattern("zzzz", testLoc).format(EPOCH_UTC), + DateTimeFormatter.ofPattern("zzzz", resourceLoc).format(EPOCH_UTC)); + } +} From f53661b1a907b685a237e12ed4b984153cf866d1 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Fri, 31 Mar 2023 11:06:22 +0000 Subject: [PATCH 028/217] 8282227: Locale information for nb is not working properly Backport-of: 3d07b3c7f01b60ff4dc38f62407c212b48883dbf --- .../util/cldr/CLDRLocaleProviderAdapter.java | 16 +++-- .../resources/cldr/NorwegianFallbackTest.java | 67 +++++++++++++++++++ 2 files changed, 78 insertions(+), 5 deletions(-) create mode 100644 test/jdk/sun/util/resources/cldr/NorwegianFallbackTest.java diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java index d2ade7bb58e..ba71f5bf8ff 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRLocaleProviderAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, 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 @@ -238,6 +238,8 @@ public List getCandidateLocales(String baseName, Locale locale) { return applyParentLocales(baseName, candidates); } + private static final Locale NB = Locale.forLanguageTag("nb"); + private static final Locale NO = Locale.forLanguageTag("no"); private List applyParentLocales(String baseName, List candidates) { // check irregular parents for (int i = 0; i < candidates.size(); i++) { @@ -247,11 +249,15 @@ private List applyParentLocales(String baseName, List candidates if (p != null && !candidates.get(i+1).equals(p)) { List applied = candidates.subList(0, i+1); - if (applied.contains(p)) { - // avoid circular recursion (could happen with nb/no case) - continue; + // Tweak for Norwegian locales, CLDR switched the canonical form of + // Norwegian Bokmal language code from "nb" to "no" in CLDR 39 + // (https://unicode-org.atlassian.net/browse/CLDR-2698) + if (p.equals(NB) || p.equals(NO)) { + applied.add(NO); + applied.add(Locale.ROOT); + } else { + applied.addAll(applyParentLocales(baseName, super.getCandidateLocales(baseName, p))); } - applied.addAll(applyParentLocales(baseName, super.getCandidateLocales(baseName, p))); return applied; } } diff --git a/test/jdk/sun/util/resources/cldr/NorwegianFallbackTest.java b/test/jdk/sun/util/resources/cldr/NorwegianFallbackTest.java new file mode 100644 index 00000000000..2b3e0c805d1 --- /dev/null +++ b/test/jdk/sun/util/resources/cldr/NorwegianFallbackTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022, 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. + */ + +/* + * @test + * @bug 8282227 + * @modules jdk.localedata + * @summary Checks Norwegian locale fallback retrieves resource bundles correctly. + * @run main/othervm -Djava.locale.providers=COMPAT NorwegianFallbackTest nb + * @run main/othervm -Djava.locale.providers=COMPAT NorwegianFallbackTest nn + * @run main/othervm -Djava.locale.providers=COMPAT NorwegianFallbackTest no + * @run main/othervm -Djava.locale.providers=CLDR NorwegianFallbackTest nb + * @run main/othervm -Djava.locale.providers=CLDR NorwegianFallbackTest nn + * @run main/othervm -Djava.locale.providers=CLDR NorwegianFallbackTest no + */ + +import java.text.DateFormatSymbols; +import java.util.List; +import java.util.Locale; +import static java.util.Calendar.SUNDAY; + +public class NorwegianFallbackTest { + + private final static String SUN_ROOT = DateFormatSymbols.getInstance(Locale.ROOT).getShortWeekdays()[SUNDAY]; + private final static List TEST_LOCS = List.of( + Locale.forLanguageTag("nb"), + Locale.forLanguageTag("nn"), + Locale.forLanguageTag("no") + ); + + public static void main(String... args) { + // Dummy instance + var startup_loc = Locale.forLanguageTag(args[0]); + DateFormatSymbols.getInstance(startup_loc); + + TEST_LOCS.stream() + .peek(l -> System.out.print("Testing locale: " + l + ", (startup locale: " + startup_loc + ")... ")) + .map(l -> DateFormatSymbols.getInstance(l).getShortWeekdays()[SUNDAY]) + .forEach(sun -> { + if (sun.equals(SUN_ROOT)) { + throw new RuntimeException("Norwegian fallback failed"); + } else { + System.out.println("Got " + "\"" + sun + "\" for Sunday short name"); + } + }); + } +} From 1253eb403268b665b79a41c784bf7f57e19328cb Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Fri, 31 Mar 2023 11:08:06 +0000 Subject: [PATCH 029/217] 8291638: Keep-Alive timeout of 0 should close connection immediately Backport-of: 26ac8366360685ef0cf3447ee7db16ba7a7fa1ec --- .../classes/sun/net/www/HeaderParser.java | 16 +++++++++++++++- .../classes/sun/net/www/http/HttpClient.java | 18 ++++++++++++++---- .../sun/net/www/http/KeepAliveCache.java | 2 ++ .../net/www/http/HttpClient/KeepAliveTest.java | 7 +------ 4 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/sun/net/www/HeaderParser.java b/src/java.base/share/classes/sun/net/www/HeaderParser.java index a4b2ab50497..e6d7435a458 100644 --- a/src/java.base/share/classes/sun/net/www/HeaderParser.java +++ b/src/java.base/share/classes/sun/net/www/HeaderParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2022, 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,6 +26,7 @@ package sun.net.www; import java.util.Iterator; +import java.util.OptionalInt; /* This is useful for the nightmare of parsing multi-part HTTP/RFC822 headers * sensibly: @@ -246,6 +247,19 @@ public int findInt(String k, int Default) { return Default; } } + + public OptionalInt findInt(String k) { + try { + String s = findValue(k); + if (s == null) { + return OptionalInt.empty(); + } + return OptionalInt.of(Integer.parseInt(s)); + } catch (Throwable t) { + return OptionalInt.empty(); + } + } + /* public static void main(String[] a) throws Exception { System.out.print("enter line to parse> "); diff --git a/src/java.base/share/classes/sun/net/www/http/HttpClient.java b/src/java.base/share/classes/sun/net/www/http/HttpClient.java index ea24babffbd..ba5e38827c7 100644 --- a/src/java.base/share/classes/sun/net/www/http/HttpClient.java +++ b/src/java.base/share/classes/sun/net/www/http/HttpClient.java @@ -29,6 +29,7 @@ import java.net.*; import java.util.Locale; import java.util.Objects; +import java.util.OptionalInt; import java.util.Properties; import java.util.concurrent.locks.ReentrantLock; @@ -127,6 +128,7 @@ private static int getDefaultPort(String proto) { * 0: the server specified no keep alive headers * -1: the server provided "Connection: keep-alive" but did not specify a * a particular time in a "Keep-Alive:" headers + * -2: the server provided "Connection: keep-alive" and timeout=0 * Positive values are the number of seconds specified by the server * in a "Keep-Alive" header */ @@ -900,11 +902,19 @@ private boolean parseHTTPHeader(MessageHeader responses, ProgressSource pi, Http if (keepAliveConnections < 0) { keepAliveConnections = usingProxy?50:5; } - keepAliveTimeout = p.findInt("timeout", -1); - if (keepAliveTimeout < -1) { - // if the server specified a negative (invalid) value - // then we set to -1, which is equivalent to no value + OptionalInt timeout = p.findInt("timeout"); + if (timeout.isEmpty()) { keepAliveTimeout = -1; + } else { + keepAliveTimeout = timeout.getAsInt(); + if (keepAliveTimeout < 0) { + // if the server specified a negative (invalid) value + // then we set to -1, which is equivalent to no value + keepAliveTimeout = -1; + } else if (keepAliveTimeout == 0) { + // handled specially to mean close connection immediately + keepAliveTimeout = -2; + } } } } else if (b[7] != '0') { diff --git a/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java b/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java index 6a61932d983..5bdd6f2c009 100644 --- a/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java +++ b/src/java.base/share/classes/sun/net/www/http/KeepAliveCache.java @@ -172,6 +172,8 @@ public Void run() { // different default for server and proxy keepAliveTimeout = http.getUsingProxy() ? 60 : 5; } + } else if (keepAliveTimeout == -2) { + keepAliveTimeout = 0; } // at this point keepAliveTimeout is the number of seconds to keep // alive, which could be 0, if the user specified 0 for the property diff --git a/test/jdk/sun/net/www/http/HttpClient/KeepAliveTest.java b/test/jdk/sun/net/www/http/HttpClient/KeepAliveTest.java index 7ec12a279b4..15983f3196a 100644 --- a/test/jdk/sun/net/www/http/HttpClient/KeepAliveTest.java +++ b/test/jdk/sun/net/www/http/HttpClient/KeepAliveTest.java @@ -24,6 +24,7 @@ /* * @test * @library /test/lib + * @bug 8291226 8291638 * @modules java.base/sun.net:+open * java.base/sun.net.www.http:+open * java.base/sun.net.www:+open @@ -1015,12 +1016,6 @@ else if (scenarioNumber >= 144 && scenarioNumber <= 159){ } private void startScenario(int scenarioNumber) throws Exception { - //test scenarios are skipped because of JDK-8291638 - if((scenarioNumber >= 112 && scenarioNumber <= 127) || (scenarioNumber >= 144 && scenarioNumber <= 159)) { - System.out.println("Scenario Skipped:"+scenarioNumber); - this.countDownLatch.countDown(); - return; - } System.out.println("serverScenarios[" + scenarioNumber + "]=" + getServerScenario(scenarioNumber)); System.out.println("clientScenarios[" + scenarioNumber + "]=" + clientScenarios[getClientScenarioNumber(scenarioNumber)]); if(expectedValues[scenarioNumber] == 0) { From 0f72c301ea416690c4148eaddaf4b7af47ff5bf9 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Fri, 31 Mar 2023 12:12:13 +0000 Subject: [PATCH 030/217] 8278434: timeouts in test java/time/test/java/time/format/TestZoneTextPrinterParser.java Backport-of: 8dc4437d002db5d025b47f48e7420e3bae55bdec --- .../cldr/CLDRTimeZoneNameProviderImpl.java | 21 ++++++++++++------- .../format/TestZoneTextPrinterParser.java | 15 +++++++------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java index d03e753a0a4..f97888a6977 100644 --- a/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java +++ b/src/java.base/share/classes/sun/util/cldr/CLDRTimeZoneNameProviderImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -151,8 +151,8 @@ private void deriveFallbackName(String[] names, int index, Locale locale, boolea // Check parent locales first if (!exists(names, index)) { - CLDRLocaleProviderAdapter clpa = (CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR); - var cands = clpa.getCandidateLocales("", locale); + var cands = ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR)) + .getCandidateLocales("", locale); for (int i = 1; i < cands.size() ; i++) { String[] parentNames = super.getDisplayNameArray(id, cands.get(i)); if (parentNames != null && !parentNames[index].isEmpty()) { @@ -162,11 +162,6 @@ private void deriveFallbackName(String[] names, int index, Locale locale, boolea } } - // Region Fallback - if (regionFormatFallback(names, index, locale)) { - return; - } - // Type Fallback if (noDST && typeFallback(names, index)) { return; @@ -185,6 +180,11 @@ private void deriveFallbackName(String[] names, int index, Locale locale, boolea } } + // Region Fallback + if (regionFormatFallback(names, index, locale)) { + return; + } + // last resort names[index] = toGMTFormat(id, index == INDEX_DST_LONG || index == INDEX_DST_SHORT, @@ -230,6 +230,11 @@ private boolean typeFallback(String[] names, int index) { } private boolean regionFormatFallback(String[] names, int index, Locale l) { + if (index % 2 == 0) { + // ignore short names + return false; + } + String id = names[INDEX_TZID]; LocaleResources lr = LocaleProviderAdapter.forType(Type.CLDR).getLocaleResources(l); ResourceBundle fd = lr.getJavaTimeFormatData(); diff --git a/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java b/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java index 77ccf37ad56..04253f3e94b 100644 --- a/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java +++ b/test/jdk/java/time/test/java/time/format/TestZoneTextPrinterParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2022, 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 @@ -49,7 +49,7 @@ /* * @test - * @bug 8081022 8151876 8166875 8189784 8206980 + * @bug 8081022 8151876 8166875 8189784 8206980 8278434 * @key randomness */ @@ -59,6 +59,11 @@ @Test public class TestZoneTextPrinterParser extends AbstractTestPrinterParser { + private static final Locale[] SAMPLE_LOCALES = { + Locale.US, Locale.UK, Locale.FRANCE, Locale.GERMANY, Locale.ITALY, Locale.forLanguageTag("es"), + Locale.forLanguageTag("pt-BR"), Locale.forLanguageTag("ru"), + Locale.CHINA, Locale.TAIWAN, Locale.JAPAN, Locale.KOREA, Locale.ROOT}; + protected static DateTimeFormatter getFormatter(Locale locale, TextStyle style) { return new DateTimeFormatterBuilder().appendZoneText(style) .toFormatter(locale) @@ -68,7 +73,6 @@ protected static DateTimeFormatter getFormatter(Locale locale, TextStyle style) public void test_printText() { Random r = RandomFactory.getRandom(); int N = 8; - Locale[] locales = Locale.getAvailableLocales(); Set zids = ZoneRulesProvider.getAvailableZoneIds(); ZonedDateTime zdt = ZonedDateTime.now(); @@ -83,7 +87,7 @@ public void test_printText() { zdt = zdt.withZoneSameLocal(ZoneId.of(zid)); TimeZone tz = TimeZone.getTimeZone(zid); boolean isDST = tz.inDaylightTime(new Date(zdt.toInstant().toEpochMilli())); - for (Locale locale : locales) { + for (Locale locale : SAMPLE_LOCALES) { String longDisplayName = tz.getDisplayName(isDST, TimeZone.LONG, locale); String shortDisplayName = tz.getDisplayName(isDST, TimeZone.SHORT, locale); if ((longDisplayName.startsWith("GMT+") && shortDisplayName.startsWith("GMT+")) @@ -116,9 +120,8 @@ private void printText(Locale locale, ZonedDateTime zdt, TextStyle style, TimeZo } public void test_ParseText() { - Locale[] locales = new Locale[] { Locale.ENGLISH, Locale.JAPANESE, Locale.FRENCH }; Set zids = ZoneRulesProvider.getAvailableZoneIds(); - for (Locale locale : locales) { + for (Locale locale : SAMPLE_LOCALES) { parseText(zids, locale, TextStyle.FULL, false); parseText(zids, locale, TextStyle.FULL, true); parseText(zids, locale, TextStyle.SHORT, false); From ac655ba08e7386876452d2ed1a797c532a1d4056 Mon Sep 17 00:00:00 2001 From: Martin Doerr Date: Fri, 31 Mar 2023 12:31:01 +0000 Subject: [PATCH 031/217] 8304880: [PPC64] VerifyOops code in C1 doesn't work with ZGC Reviewed-by: rrich Backport-of: 695683b5b15c69a56fe7ee1a93482fe7c3530ca8 --- src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index af9a856ae08..2b7094f71aa 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -828,7 +828,6 @@ int LIR_Assembler::load(Register base, int offset, LIR_Opr to_reg, BasicType typ } else { __ ld(to_reg->as_register(), offset, base); } - __ verify_oop(to_reg->as_register(), FILE_AND_LINE); break; } case T_FLOAT: __ lfs(to_reg->as_float_reg(), offset, base); break; @@ -859,7 +858,6 @@ int LIR_Assembler::load(Register base, Register disp, LIR_Opr to_reg, BasicType } else { __ ldx(to_reg->as_register(), base, disp); } - __ verify_oop(to_reg->as_register(), FILE_AND_LINE); break; } case T_FLOAT: __ lfsx(to_reg->as_float_reg() , base, disp); break; From 47e4dba6a266caa7a3d6305113d903e657a6fb25 Mon Sep 17 00:00:00 2001 From: Glavo Date: Mon, 3 Apr 2023 00:04:29 +0000 Subject: [PATCH 032/217] 8278834: Error "Cannot read field "sym" because "this.lvar[od]" is null" when compiling Reviewed-by: phh Backport-of: be0538d7c8e2cbfa599dbcb4c5c69533678a8421 --- .../sun/tools/javac/comp/TransPatterns.java | 3 + .../javac/patterns/BindingsInitializer.java | 164 ++++++++++++++++++ 2 files changed, 167 insertions(+) create mode 100644 test/langtools/tools/javac/patterns/BindingsInitializer.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java index fda59d6ddaa..65a8047a33d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java @@ -664,11 +664,14 @@ public void visitLambda(JCLambda tree) { @Override public void visitClassDef(JCClassDecl tree) { ClassSymbol prevCurrentClass = currentClass; + MethodSymbol prevMethodSym = currentMethodSym; try { currentClass = tree.sym; + currentMethodSym = null; super.visitClassDef(tree); } finally { currentClass = prevCurrentClass; + currentMethodSym = prevMethodSym; } } diff --git a/test/langtools/tools/javac/patterns/BindingsInitializer.java b/test/langtools/tools/javac/patterns/BindingsInitializer.java new file mode 100644 index 00000000000..eaf550c3daf --- /dev/null +++ b/test/langtools/tools/javac/patterns/BindingsInitializer.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2022, 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. + */ + +/* + * @test + * @bug 8278834 + * @summary Verify pattern matching nested inside initializers of classes nested in methods + * works correctly. + * @library /tools/lib /tools/javac/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.main + * jdk.compiler/com.sun.tools.javac.util + * @build toolbox.ToolBox toolbox.JavacTask + * @build combo.ComboTestHelper + * @compile BindingsInitializer.java + * @run main BindingsInitializer + */ + +import combo.ComboInstance; +import combo.ComboParameter; +import combo.ComboTask; +import combo.ComboTestHelper; +import java.nio.file.Path; +import java.nio.file.Paths; +import toolbox.ToolBox; + +public class BindingsInitializer extends ComboInstance { + protected ToolBox tb; + + BindingsInitializer() { + super(); + tb = new ToolBox(); + } + + public static void main(String... args) throws Exception { + new ComboTestHelper() + .withDimension("OUTER", (x, outer) -> x.outer = outer, Outer.values()) + .withDimension("MIDDLE", (x, middle) -> x.middle = middle, Middle.values()) + .withDimension("INNER", (x, inner) -> x.inner = inner, Inner.values()) + .withDimension("TEST", (x, test) -> x.test = test, Test.values()) + .run(BindingsInitializer::new); + } + + private Outer outer; + private Middle middle; + private Inner inner; + private Test test; + + private static final String MAIN_TEMPLATE = + """ + public class Test { + private static Object obj = ""; + #{OUTER} + } + """; + + @Override + protected void doWork() throws Throwable { + Path base = Paths.get("."); + + ComboTask task = newCompilationTask() + .withSourceFromTemplate(MAIN_TEMPLATE, pname -> switch (pname) { + case "OUTER" -> outer; + case "MIDDLE" -> middle; + case "INNER" -> inner; + case "TESST" -> test; + default -> throw new UnsupportedOperationException(pname); + }); + + task.generate(result -> { + if (result.hasErrors()) { + throw new AssertionError("Unexpected result: " + result.compilationInfo()); + } + }); + } + + public enum Outer implements ComboParameter { + NONE("#{MIDDLE}"), + STATIC_CLASS("static class Nested { #{MIDDLE} }"), + CLASS("class Inner { #{MIDDLE} }"); + private final String code; + + private Outer(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } + + public enum Middle implements ComboParameter { + STATIC_INIT("static { #{INNER} }"), + INIT("{ #{INNER} }"), + METHOD("void test() { #{INNER} }"); + private final String code; + + private Middle(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } + + public enum Inner implements ComboParameter { + DIRECT("#{TEST}"), + CLASS_STATIC_INIT("class C { static { #{TEST} } }"), + CLASS_INIT("class C { { #{TEST} } }"), + CLASS_METHOD("class C { void t() { #{TEST} } }"), + ANNONYMOUS_CLASS_STATIC_INIT("new Object() { static { #{TEST} } };"), + ANNONYMOUS_CLASS_INIT("new Object() { { #{TEST} } };"), + ANNONYMOUS_CLASS_METHOD("new Object() { void t() { #{TEST} } };"); + private final String code; + + private Inner(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } + + public enum Test implements ComboParameter { + TEST("if (obj instanceof String str) System.err.println(str);"); + private final String code; + + private Test(String code) { + this.code = code; + } + + @Override + public String expand(String optParameter) { + return code; + } + } +} From 4c3aecba20edb406ef68f3f87f00fbf12dcfebaf Mon Sep 17 00:00:00 2001 From: Dan Lutker Date: Tue, 4 Apr 2023 18:36:35 +0000 Subject: [PATCH 033/217] 8294281: Allow warnings to be disabled on a per-file basis Backport-of: e45f3d5176e4affaa08480b560ca983fdbcb2846 --- make/common/NativeCompilation.gmk | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index 0f315019d0e..215d90d17e9 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -343,10 +343,15 @@ define SetupCompileNativeFileBody endif endif + ifneq ($(DISABLE_WARNING_PREFIX), ) + $1_WARNINGS_FLAGS := $$(addprefix $(DISABLE_WARNING_PREFIX), \ + $$($$($1_BASE)_DISABLED_WARNINGS_$(TOOLCHAIN_TYPE)_$$($1_FILENAME))) + endif + $1_BASE_CFLAGS := $$($$($1_BASE)_CFLAGS) $$($$($1_BASE)_EXTRA_CFLAGS) \ - $$($$($1_BASE)_SYSROOT_CFLAGS) + $$($$($1_BASE)_SYSROOT_CFLAGS) $$($1_WARNINGS_FLAGS) $1_BASE_CXXFLAGS := $$($$($1_BASE)_CXXFLAGS) $$($$($1_BASE)_EXTRA_CXXFLAGS) \ - $$($$($1_BASE)_SYSROOT_CFLAGS) $$($1_EXTRA_CXXFLAGS) + $$($$($1_BASE)_SYSROOT_CFLAGS) $$($1_EXTRA_CXXFLAGS) $$($1_WARNINGS_FLAGS) $1_BASE_ASFLAGS := $$($$($1_BASE)_ASFLAGS) $$($$($1_BASE)_EXTRA_ASFLAGS) ifneq ($$(filter %.c, $$($1_FILENAME)), ) From 768bed2ccf0c019304bafa7b5a0194f45796bf53 Mon Sep 17 00:00:00 2001 From: Dan Lutker Date: Tue, 4 Apr 2023 19:03:36 +0000 Subject: [PATCH 034/217] 8293887: AArch64 build failure with GCC 12 due to maybe-uninitialized warning in libfdlibm k_rem_pio2.c Backport-of: 02ea338177df781912dc782e32200eaf4731a0da --- make/modules/java.base/lib/CoreLibraries.gmk | 1 + 1 file changed, 1 insertion(+) diff --git a/make/modules/java.base/lib/CoreLibraries.gmk b/make/modules/java.base/lib/CoreLibraries.gmk index e7188218df3..bb09d8cf8a2 100644 --- a/make/modules/java.base/lib/CoreLibraries.gmk +++ b/make/modules/java.base/lib/CoreLibraries.gmk @@ -49,6 +49,7 @@ $(eval $(call SetupNativeCompilation, BUILD_LIBFDLIBM, \ CFLAGS_windows_debug := -DLOGGING, \ CFLAGS_aix := -qfloat=nomaf, \ DISABLED_WARNINGS_gcc := sign-compare misleading-indentation array-bounds, \ + DISABLED_WARNINGS_gcc_k_rem_pio2.c := maybe-uninitialized, \ DISABLED_WARNINGS_clang := sign-compare misleading-indentation, \ DISABLED_WARNINGS_microsoft := 4146 4244 4018, \ ARFLAGS := $(ARFLAGS), \ From ce1288038d51f1f1d55f724f17b0185531b7b7ad Mon Sep 17 00:00:00 2001 From: Ilarion Nakonechnyy Date: Thu, 13 Apr 2023 11:48:43 +0000 Subject: [PATCH 035/217] 8302491: NoClassDefFoundError omits the original cause of an error Reviewed-by: phh Backport-of: 5685107579f0f00b5eae881311315cec34c1ddcb --- src/hotspot/share/classfile/javaClasses.cpp | 66 ++++++++++++--------- src/hotspot/share/classfile/javaClasses.hpp | 2 +- src/hotspot/share/oops/instanceKlass.cpp | 12 ++-- 3 files changed, 44 insertions(+), 36 deletions(-) diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 793beb479ac..9c0309384bb 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -2719,49 +2719,57 @@ void java_lang_Throwable::get_stack_trace_elements(Handle throwable, } } -Handle java_lang_Throwable::get_cause_with_stack_trace(Handle throwable, TRAPS) { - // Call to JVM to fill in the stack trace and clear declaringClassObject to - // not keep classes alive in the stack trace. - // call this: public StackTraceElement[] getStackTrace() +Handle java_lang_Throwable::create_initialization_error(JavaThread* current, Handle throwable) { + // Creates an ExceptionInInitializerError to be recorded as the initialization error when class initialization + // failed due to the passed in 'throwable'. We cannot save 'throwable' directly due to issues with keeping alive + // all objects referenced via its stacktrace. So instead we save a new EIIE instance, with the same message and + // symbolic stacktrace of 'throwable'. assert(throwable.not_null(), "shouldn't be"); - JavaValue result(T_ARRAY); - JavaCalls::call_virtual(&result, throwable, - vmClasses::Throwable_klass(), - vmSymbols::getStackTrace_name(), - vmSymbols::getStackTrace_signature(), - CHECK_NH); - Handle stack_trace(THREAD, result.get_oop()); - assert(stack_trace->is_objArray(), "Should be an array"); - - // Throw ExceptionInInitializerError as the cause with this exception in - // the message and stack trace. - - // Now create the message with the original exception and thread name. + // Now create the message from the original exception and thread name. Symbol* message = java_lang_Throwable::detail_message(throwable()); - ResourceMark rm(THREAD); + ResourceMark rm(current); stringStream st; st.print("Exception %s%s ", throwable()->klass()->name()->as_klass_external_name(), message == nullptr ? "" : ":"); if (message == NULL) { - st.print("[in thread \"%s\"]", THREAD->name()); + st.print("[in thread \"%s\"]", current->name()); } else { - st.print("%s [in thread \"%s\"]", message->as_C_string(), THREAD->name()); + st.print("%s [in thread \"%s\"]", message->as_C_string(), current->name()); } Symbol* exception_name = vmSymbols::java_lang_ExceptionInInitializerError(); - Handle h_cause = Exceptions::new_exception(THREAD, exception_name, st.as_string()); - - // If new_exception returns a different exception while creating the exception, return null. - if (h_cause->klass()->name() != exception_name) { + Handle init_error = Exceptions::new_exception(current, exception_name, st.as_string()); + // If new_exception returns a different exception while creating the exception, + // abandon the attempt to save the initialization error and return null. + if (init_error->klass()->name() != exception_name) { log_info(class, init)("Exception thrown while saving initialization exception %s", - h_cause->klass()->external_name()); + init_error->klass()->external_name()); return Handle(); } - java_lang_Throwable::set_stacktrace(h_cause(), stack_trace()); - // Clear backtrace because the stacktrace should be used instead. - set_backtrace(h_cause(), NULL); - return h_cause; + + // Call to java to fill in the stack trace and clear declaringClassObject to + // not keep classes alive in the stack trace. + // call this: public StackTraceElement[] getStackTrace() + JavaValue result(T_ARRAY); + JavaCalls::call_virtual(&result, throwable, + vmClasses::Throwable_klass(), + vmSymbols::getStackTrace_name(), + vmSymbols::getStackTrace_signature(), + current); + if (!current->has_pending_exception()){ + Handle stack_trace(current, result.get_oop()); + assert(stack_trace->is_objArray(), "Should be an array"); + java_lang_Throwable::set_stacktrace(init_error(), stack_trace()); + // Clear backtrace because the stacktrace should be used instead. + set_backtrace(init_error(), nullptr); + } else { + log_info(class, init)("Exception thrown while getting stack trace for initialization exception %s", + init_error->klass()->external_name()); + current->clear_pending_exception(); + } + + return init_error; } bool java_lang_Throwable::get_top_method_and_bci(oop throwable, Method** method, int* bci) { diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 583e5473c9a..217f5f5ad91 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -569,7 +569,7 @@ class java_lang_Throwable: AllStatic { static void get_stack_trace_elements(Handle throwable, objArrayHandle stack_trace, TRAPS); // For recreating class initialization error exceptions. - static Handle get_cause_with_stack_trace(Handle throwable, TRAPS); + static Handle create_initialization_error(JavaThread* current, Handle throwable); // Printing static void print(oop throwable, outputStream* st); diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index bf9416915ce..5c71a49c30b 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -1035,18 +1035,18 @@ void InstanceKlass::add_initialization_error(JavaThread* current, Handle excepti // If the initialization error is OOM, this might not work, but if GC kicks in // this would be still be helpful. JavaThread* THREAD = current; - Handle cause = java_lang_Throwable::get_cause_with_stack_trace(exception, THREAD); - if (HAS_PENDING_EXCEPTION || cause.is_null()) { - CLEAR_PENDING_EXCEPTION; + Handle init_error = java_lang_Throwable::create_initialization_error(current, exception); + ResourceMark rm(THREAD); + if (init_error.is_null()) { + log_trace(class, init)("Initialization error is null for class %s", external_name()); return; } MutexLocker ml(THREAD, ClassInitError_lock); - OopHandle elem = OopHandle(Universe::vm_global(), cause()); - bool created = false; + OopHandle elem = OopHandle(Universe::vm_global(), init_error()); + bool created; _initialization_error_table.put_if_absent(this, elem, &created); assert(created, "Initialization is single threaded"); - ResourceMark rm(THREAD); log_trace(class, init)("Initialization error added for class %s", external_name()); } From aeb7cf503994c9ed1f227f3c0ea0704a1dc31cca Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Thu, 13 Apr 2023 15:11:04 +0000 Subject: [PATCH 036/217] 8274864: Remove Amman/Cairo hacks in ZoneInfoFile Backport-of: ec199072c5867624d66840238cc8828e16ae8da7 --- .../sun/util/calendar/ZoneInfoFile.java | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java index 6f6e190efcd..ef278203182 100644 --- a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -608,34 +608,6 @@ private static ZoneInfo getZoneInfo(String zoneId, params[8] = endRule.secondOfDay * 1000; params[9] = toSTZTime[endRule.timeDefinition]; dstSavings = (startRule.offsetAfter - startRule.offsetBefore) * 1000; - - // Note: known mismatching -> Asia/Amman - // ZoneInfo : startDayOfWeek=5 <= Thursday - // startTime=86400000 <= 24 hours - // This: startDayOfWeek=6 - // startTime=0 - // Similar workaround needs to be applied to Africa/Cairo and - // its endDayOfWeek and endTime - // Below is the workarounds, it probably slows down everyone a little - if (params[2] == 6 && params[3] == 0 && - (zoneId.equals("Asia/Amman"))) { - params[2] = 5; - params[3] = 86400000; - } - // Additional check for startDayOfWeek=6 and starTime=86400000 - // is needed for Asia/Amman; - if (params[2] == 7 && params[3] == 0 && - (zoneId.equals("Asia/Amman"))) { - params[2] = 6; // Friday - params[3] = 86400000; // 24h - } - //endDayOfWeek and endTime workaround - if (params[7] == 6 && params[8] == 0 && - (zoneId.equals("Africa/Cairo"))) { - params[7] = 5; - params[8] = 86400000; - } - } else if (nTrans > 0) { // only do this if there is something in table already if (lastyear < LASTYEAR) { // ZoneInfo has an ending entry for 2037 @@ -908,7 +880,6 @@ private static class ZoneOffsetTransitionRule { this.dow = dowByte == 0 ? -1 : dowByte; this.secondOfDay = timeByte == 31 ? in.readInt() : timeByte * 3600; this.timeDefinition = (data & (3 << 12)) >>> 12; - this.standardOffset = stdByte == 255 ? in.readInt() : (stdByte - 128) * 900; this.offsetBefore = beforeByte == 3 ? in.readInt() : standardOffset + beforeByte * 1800; this.offsetAfter = afterByte == 3 ? in.readInt() : standardOffset + afterByte * 1800; From 8bf2cf2d7c7f716676e7827591ce052541b7be3a Mon Sep 17 00:00:00 2001 From: Joshua Cao Date: Thu, 13 Apr 2023 16:57:48 +0000 Subject: [PATCH 037/217] 8305721: add `make compile-commands` artifacts to .gitignore Reviewed-by: phh Backport-of: 9e20382311c58bd172abc98bc0a6757c3a64dda1 --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 6787b232535..d0736707b80 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,5 @@ NashornProfile.txt /src/utils/LogCompilation/target/ /.project/ /.settings/ +/compile_commands.json +/.cache From 01cf112cbb5603c285d0d4bb54a840e4585f8735 Mon Sep 17 00:00:00 2001 From: Thomas Stuefe Date: Fri, 14 Apr 2023 09:16:29 +0000 Subject: [PATCH 038/217] 8305711: Arm: C2 always enters slowpath for monitorexit Backport-of: c67bbcea92919fea9b6f7bbcde8ba4488289d174 --- src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp index 2211d5c5fa3..3d205fe7062 100644 --- a/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp +++ b/src/hotspot/cpu/arm/c2_MacroAssembler_arm.cpp @@ -160,7 +160,7 @@ void C2_MacroAssembler::fast_unlock(Register Roop, Register Rbox, Register Rscra // Restore the object header bool allow_fallthrough_on_failure = true; bool one_shot = true; - cas_for_lock_release(Rmark, Rbox, Roop, Rscratch, done, allow_fallthrough_on_failure, one_shot); + cas_for_lock_release(Rbox, Rmark, Roop, Rscratch, done, allow_fallthrough_on_failure, one_shot); bind(done); } From acbac0d169138f028841bc264d308a429d0a5370 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Sun, 16 Apr 2023 14:16:26 +0000 Subject: [PATCH 039/217] 8288589: Files.readString ignores encoding errors for UTF-16 Backport-of: 2728770e3d73bb11c4d6e54b5aff91588a1a780b --- .../share/classes/java/lang/String.java | 41 +++++---- .../jdk/java/lang/String/NewStringNoRepl.java | 50 ----------- test/jdk/java/lang/String/NoReplTest.java | 85 +++++++++++++++++++ .../java/nio/file/Files/ReadWriteString.java | 75 +++++++++++----- 4 files changed, 163 insertions(+), 88 deletions(-) delete mode 100644 test/jdk/java/lang/String/NewStringNoRepl.java create mode 100644 test/jdk/java/lang/String/NoReplTest.java diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 884a117727e..de62d82a331 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -651,6 +651,8 @@ public String(byte[] bytes, int offset, int length, Charset charset) { // decode using CharsetDecoder int en = scale(length, cd.maxCharsPerByte()); + cd.onMalformedInput(CodingErrorAction.REPLACE) + .onUnmappableCharacter(CodingErrorAction.REPLACE); char[] ca = new char[en]; if (charset.getClass().getClassLoader0() != null && System.getSecurityManager() != null) { @@ -658,7 +660,13 @@ public String(byte[] bytes, int offset, int length, Charset charset) { offset = 0; } - int caLen = decodeWithDecoder(cd, ca, bytes, offset, length); + int caLen; + try { + caLen = decodeWithDecoder(cd, ca, bytes, offset, length); + } catch (CharacterCodingException x) { + // Substitution is enabled, so this shouldn't happen + throw new Error(x); + } if (COMPACT_STRINGS) { byte[] bs = StringUTF16.compress(ca, 0, caLen); if (bs != null) { @@ -779,7 +787,13 @@ private static String newStringNoRepl1(byte[] src, Charset cs) { System.getSecurityManager() != null) { src = Arrays.copyOf(src, len); } - int caLen = decodeWithDecoder(cd, ca, src, 0, src.length); + int caLen; + try { + caLen = decodeWithDecoder(cd, ca, src, 0, src.length); + } catch (CharacterCodingException x) { + // throw via IAE + throw new IllegalArgumentException(x); + } if (COMPACT_STRINGS) { byte[] bs = StringUTF16.compress(ca, 0, caLen); if (bs != null) { @@ -1189,23 +1203,16 @@ private static int decodeUTF8_UTF16(byte[] src, int sp, int sl, byte[] dst, int return dp; } - private static int decodeWithDecoder(CharsetDecoder cd, char[] dst, byte[] src, int offset, int length) { + private static int decodeWithDecoder(CharsetDecoder cd, char[] dst, byte[] src, int offset, int length) + throws CharacterCodingException { ByteBuffer bb = ByteBuffer.wrap(src, offset, length); CharBuffer cb = CharBuffer.wrap(dst, 0, dst.length); - cd.onMalformedInput(CodingErrorAction.REPLACE) - .onUnmappableCharacter(CodingErrorAction.REPLACE); - try { - CoderResult cr = cd.decode(bb, cb, true); - if (!cr.isUnderflow()) - cr.throwException(); - cr = cd.flush(cb); - if (!cr.isUnderflow()) - cr.throwException(); - } catch (CharacterCodingException x) { - // Substitution is always enabled, - // so this shouldn't happen - throw new Error(x); - } + CoderResult cr = cd.decode(bb, cb, true); + if (!cr.isUnderflow()) + cr.throwException(); + cr = cd.flush(cb); + if (!cr.isUnderflow()) + cr.throwException(); return cb.position(); } diff --git a/test/jdk/java/lang/String/NewStringNoRepl.java b/test/jdk/java/lang/String/NewStringNoRepl.java deleted file mode 100644 index ae1a26393cc..00000000000 --- a/test/jdk/java/lang/String/NewStringNoRepl.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (c) 2022, 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. - */ - -/* - * @test - * @bug 8286287 - * @summary Verifies newStringNoRepl() does not throw an Error. - */ - -import java.io.IOException; -import java.nio.file.Files; -import java.util.HexFormat; -import static java.nio.charset.StandardCharsets.UTF_16; - -public class NewStringNoRepl { - private final static byte[] MALFORMED_UTF16 = {(byte)0x00, (byte)0x20, (byte)0x00}; - - public static void main(String... args) throws IOException { - var f = Files.createTempFile(null, null); - try (var fos = Files.newOutputStream(f)) { - fos.write(MALFORMED_UTF16); - } - System.out.println("Returned bytes: " + - HexFormat.of() - .withPrefix("x") - .withUpperCase() - .formatHex(Files.readString(f, UTF_16).getBytes(UTF_16))); - Files.delete(f); - } -} diff --git a/test/jdk/java/lang/String/NoReplTest.java b/test/jdk/java/lang/String/NoReplTest.java new file mode 100644 index 00000000000..1817a1ffe73 --- /dev/null +++ b/test/jdk/java/lang/String/NoReplTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022, 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. + */ + +/* + * @test + * @bug 8286287 8288589 + * @summary Tests for *NoRepl() shared secret methods. + * @run testng NoReplTest + * @modules jdk.charsets + */ + +import java.io.IOException; +import java.nio.charset.CharacterCodingException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.HexFormat; +import static java.nio.charset.StandardCharsets.UTF_16; + +import org.testng.annotations.Test; + +@Test +public class NoReplTest { + private final static byte[] MALFORMED_UTF16 = {(byte)0x00, (byte)0x20, (byte)0x00}; + private final static String MALFORMED_WINDOWS_1252 = "\u0080\u041e"; + private final static Charset WINDOWS_1252 = Charset.forName("windows-1252"); + + /** + * Verifies newStringNoRepl() throws a CharacterCodingException. + * The method is invoked by `Files.readString()` method. + */ + @Test + public void newStringNoReplTest() throws IOException { + var f = Files.createTempFile(null, null); + try (var fos = Files.newOutputStream(f)) { + fos.write(MALFORMED_UTF16); + var read = Files.readString(f, UTF_16); + throw new RuntimeException("Exception should be thrown for a malformed input. Bytes read: " + + HexFormat.of() + .withPrefix("x") + .withUpperCase() + .formatHex(read.getBytes(UTF_16))); + } catch (CharacterCodingException cce) { + // success + } finally { + Files.delete(f); + } + } + + /** + * Verifies getBytesNoRepl() throws a CharacterCodingException. + * The method is invoked by `Files.writeString()` method. + */ + @Test + public void getBytesNoReplTest() throws IOException { + var f = Files.createTempFile(null, null); + try { + Files.writeString(f, MALFORMED_WINDOWS_1252, WINDOWS_1252); + throw new RuntimeException("Exception should be thrown"); + } catch (CharacterCodingException cce) { + // success + } finally { + Files.delete(f); + } + } +} diff --git a/test/jdk/java/nio/file/Files/ReadWriteString.java b/test/jdk/java/nio/file/Files/ReadWriteString.java index 37c069c6aa9..885cbb771dc 100644 --- a/test/jdk/java/nio/file/Files/ReadWriteString.java +++ b/test/jdk/java/nio/file/Files/ReadWriteString.java @@ -24,10 +24,12 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.nio.charset.Charset; +import java.nio.charset.CharacterCodingException; import java.nio.charset.MalformedInputException; import java.nio.charset.UnmappableCharacterException; -import static java.nio.charset.StandardCharsets.US_ASCII; import static java.nio.charset.StandardCharsets.ISO_8859_1; +import static java.nio.charset.StandardCharsets.US_ASCII; +import static java.nio.charset.StandardCharsets.UTF_16; import static java.nio.charset.StandardCharsets.UTF_8; import java.nio.file.Files; import java.nio.file.OpenOption; @@ -46,7 +48,7 @@ import org.testng.annotations.Test; /* @test - * @bug 8201276 8205058 8209576 8287541 + * @bug 8201276 8205058 8209576 8287541 8288589 * @build ReadWriteString PassThroughFileSystem * @run testng ReadWriteString * @summary Unit test for methods for Files readString and write methods. @@ -60,6 +62,8 @@ public class ReadWriteString { final String TEXT_UNICODE = "\u201CHello\u201D"; final String TEXT_ASCII = "ABCDEFGHIJKLMNOPQRSTUVWXYZ\n abcdefghijklmnopqrstuvwxyz\n 1234567890\n"; private static final String JA_STRING = "\u65e5\u672c\u8a9e\u6587\u5b57\u5217"; + private static final Charset WINDOWS_1252 = Charset.forName("windows-1252"); + private static final Charset WINDOWS_31J = Charset.forName("windows-31j"); static byte[] data = getData(); @@ -88,14 +92,14 @@ static byte[] getData() { */ @DataProvider(name = "malformedWrite") public Object[][] getMalformedWrite() throws IOException { - Path path = Files.createTempFile("malformedWrite", null); + Path path = Files.createFile(Path.of("malformedWrite")); return new Object[][]{ {path, "\ud800", null}, //the default Charset is UTF_8 {path, "\u00A0\u00A1", US_ASCII}, {path, "\ud800", UTF_8}, {path, JA_STRING, ISO_8859_1}, - {path, "\u041e", Charset.forName("windows-1252")}, // cyrillic capital letter O - {path, "\u091c", Charset.forName("windows-31j")}, // devanagari letter ja + {path, "\u041e", WINDOWS_1252}, // cyrillic capital letter O + {path, "\u091c", WINDOWS_31J}, // devanagari letter ja }; } @@ -105,13 +109,26 @@ public Object[][] getMalformedWrite() throws IOException { */ @DataProvider(name = "illegalInput") public Object[][] getIllegalInput() throws IOException { - Path path = Files.createTempFile("illegalInput", null); + Path path = Files.createFile(Path.of("illegalInput")); return new Object[][]{ {path, data, ISO_8859_1, null}, {path, data, ISO_8859_1, UTF_8} }; } + /* + * DataProvider for illegal input bytes test + */ + @DataProvider(name = "illegalInputBytes") + public Object[][] getIllegalInputBytes() throws IOException { + return new Object[][]{ + {new byte[] {(byte)0x00, (byte)0x20, (byte)0x00}, UTF_16, MalformedInputException.class}, + {new byte[] {-50}, UTF_16, MalformedInputException.class}, + {new byte[] {(byte)0x81}, WINDOWS_1252, UnmappableCharacterException.class}, // unused in Cp1252 + {new byte[] {(byte)0x81, (byte)0xff}, WINDOWS_31J, UnmappableCharacterException.class}, // invalid trailing byte + }; + } + /* * DataProvider for writeString test * Writes the data using both the existing and new method and compares the results. @@ -143,16 +160,9 @@ public Object[][] getReadString() { @BeforeClass void setup() throws IOException { - testFiles[0] = Files.createTempFile("readWriteString", null); - testFiles[1] = Files.createTempFile("writeString_file1", null); - testFiles[2] = Files.createTempFile("writeString_file2", null); - } - - @AfterClass - void cleanup() throws IOException { - for (Path path : testFiles) { - Files.deleteIfExists(path); - } + testFiles[0] = Files.createFile(Path.of("readWriteString")); + testFiles[1] = Files.createFile(Path.of("writeString_file1")); + testFiles[2] = Files.createFile(Path.of("writeString_file2")); } /** @@ -241,11 +251,10 @@ public void testReadString(Path path, String text, Charset cs, Charset cs2) thro */ @Test(dataProvider = "malformedWrite", expectedExceptions = UnmappableCharacterException.class) public void testMalformedWrite(Path path, String s, Charset cs) throws IOException { - path.toFile().deleteOnExit(); if (cs == null) { - Files.writeString(path, s, CREATE); + Files.writeString(path, s); } else { - Files.writeString(path, s, cs, CREATE); + Files.writeString(path, s, cs); } } @@ -261,9 +270,8 @@ public void testMalformedWrite(Path path, String s, Charset cs) throws IOExcepti */ @Test(dataProvider = "illegalInput", expectedExceptions = MalformedInputException.class) public void testMalformedRead(Path path, byte[] data, Charset csWrite, Charset csRead) throws IOException { - path.toFile().deleteOnExit(); String temp = new String(data, csWrite); - Files.writeString(path, temp, csWrite, CREATE); + Files.writeString(path, temp, csWrite); if (csRead == null) { Files.readString(path); } else { @@ -271,6 +279,31 @@ public void testMalformedRead(Path path, byte[] data, Charset csWrite, Charset c } } + /** + * Verifies that IOException is thrown when reading a file containing + * illegal bytes + * + * @param data the data used for the test + * @param csRead the Charset to use for reading the file + * @param expected exception class + * @throws IOException when the Charset used for reading the file is incorrect + */ + @Test(dataProvider = "illegalInputBytes") + public void testMalformedReadBytes(byte[] data, Charset csRead, Class expected) + throws IOException { + Path path = Path.of("illegalInputBytes"); + Files.write(path, data); + try { + Files.readString(path, csRead); + } catch (MalformedInputException | UnmappableCharacterException e) { + if (expected.isInstance(e)) { + // success + return; + } + } + throw new RuntimeException("An instance of " + expected + " should be thrown"); + } + private void checkNullPointerException(Callable c) { try { c.call(); From f8408c7896952320f8b9dc5b515c697d81639197 Mon Sep 17 00:00:00 2001 From: Andrew John Hughes Date: Mon, 17 Apr 2023 12:27:28 +0000 Subject: [PATCH 040/217] 8305113: (tz) Update Timezone Data to 2023c Reviewed-by: phh Backport-of: ed9592c6e81f82e2bf6508ce45ba15aad8232181 --- make/data/tzdata/VERSION | 2 +- make/data/tzdata/africa | 71 +++++--- make/data/tzdata/antarctica | 2 +- make/data/tzdata/asia | 166 +++++++++++++++++- make/data/tzdata/australasia | 44 ++--- make/data/tzdata/backward | 1 + make/data/tzdata/europe | 59 +++---- make/data/tzdata/iso3166.tab | 2 +- make/data/tzdata/leapseconds | 8 +- make/data/tzdata/northamerica | 32 ++-- make/data/tzdata/southamerica | 2 +- make/data/tzdata/zone.tab | 29 ++- .../sun/util/calendar/ZoneInfoFile.java | 11 ++ .../sun/util/resources/TimeZoneNames.java | 6 +- .../java/util/TimeZone/TimeZoneData/VERSION | 2 +- .../util/TimeZone/TimeZoneData/aliases.txt | 1 + .../TimeZone/TimeZoneData/displaynames.txt | 3 +- test/jdk/java/util/TimeZone/TimeZoneTest.java | 6 +- 18 files changed, 305 insertions(+), 142 deletions(-) diff --git a/make/data/tzdata/VERSION b/make/data/tzdata/VERSION index 0f328a4a7ff..66bd061e8bc 100644 --- a/make/data/tzdata/VERSION +++ b/make/data/tzdata/VERSION @@ -21,4 +21,4 @@ # or visit www.oracle.com if you need additional information or have any # questions. # -tzdata2022g +tzdata2023c diff --git a/make/data/tzdata/africa b/make/data/tzdata/africa index 830d7d10b7e..a73405fdb01 100644 --- a/make/data/tzdata/africa +++ b/make/data/tzdata/africa @@ -344,6 +344,14 @@ Rule Egypt 2007 only - Sep Thu>=1 24:00 0 - # From Mina Samuel (2016-07-04): # Egyptian government took the decision to cancel the DST, +# From Ahmad ElDardiry (2023-03-01): +# Egypt officially announced today that daylight savings will be +# applied from last Friday of April to last Thursday of October. +# From Paul Eggert (2023-03-01): +# Assume transitions are at 00:00 and 24:00 respectively. +# From Amir Adib (2023-03-07): +# https://www.facebook.com/EgyptianCabinet/posts/638829614954129/ + Rule Egypt 2008 only - Aug lastThu 24:00 0 - Rule Egypt 2009 only - Aug 20 24:00 0 - Rule Egypt 2010 only - Aug 10 24:00 0 - @@ -353,6 +361,8 @@ Rule Egypt 2014 only - May 15 24:00 1:00 S Rule Egypt 2014 only - Jun 26 24:00 0 - Rule Egypt 2014 only - Jul 31 24:00 1:00 S Rule Egypt 2014 only - Sep lastThu 24:00 0 - +Rule Egypt 2023 max - Apr lastFri 0:00 1:00 S +Rule Egypt 2023 max - Oct lastThu 24:00 0 - # Zone NAME STDOFF RULES FORMAT [UNTIL] #STDOFF 2:05:08.9 @@ -452,7 +462,7 @@ Zone Africa/Nairobi 2:27:16 - LMT 1908 May # President William R. Tolbert, Jr., July 23, 1971-July 31, 1972. # Monrovia: Executive Mansion. # -# Use the abbreviation "MMT" before 1972, as the more-accurate numeric +# Use the abbreviation "MMT" before 1972, as the more accurate numeric # abbreviation "-004430" would be one byte over the POSIX limit. # # Zone NAME STDOFF RULES FORMAT [UNTIL] @@ -589,8 +599,8 @@ Zone Africa/Tripoli 0:52:44 - LMT 1920 # DST the coming summer... # # Some sources, in French: -# http://www.defimedia.info/news/946/Rashid-Beebeejaun-:-%C2%AB-L%E2%80%99heure-d%E2%80%99%C3%A9t%C3%A9-ne-sera-pas-appliqu%C3%A9e-cette-ann%C3%A9e-%C2%BB -# http://lexpress.mu/Story/3398~Beebeejaun---Les-objectifs-d-%C3%A9conomie-d-%C3%A9nergie-de-l-heure-d-%C3%A9t%C3%A9-ont-%C3%A9t%C3%A9-atteints- +# http://www.defimedia.info/news/946/Rashid-Beebeejaun-:-«-L%E2%80%99heure-d%E2%80%99été-ne-sera-pas-appliquée-cette-année-» +# http://lexpress.mu/Story/3398~Beebeejaun---Les-objectifs-d-économie-d-énergie-de-l-heure-d-été-ont-été-atteints- # # Our wrap-up: # https://www.timeanddate.com/news/time/mauritius-dst-will-not-repeat.html @@ -721,7 +731,7 @@ Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis # More articles in the press # https://www.yabiladi.com/articles/details/5058/secret-l-heure-d-ete-maroc-leve.html # http://www.lematin.ma/Actualite/Express/Article.asp?id=148923 -# http://www.lavieeco.com/actualite/Le-Maroc-passe-sur-GMT%2B1-a-partir-de-dim +# http://www.lavieeco.com/actualite/Le-Maroc-passe-sur-GMT+1-a-partir-de-dim # From Petr Machata (2011-03-30): # They have it written in English here: @@ -736,7 +746,7 @@ Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis # According to Infomédiaire web site from Morocco (infomediaire.ma), # on March 9, 2012, (in French) Heure légale: # Le Maroc adopte officiellement l'heure d'été -# http://www.infomediaire.ma/news/maroc/heure-l%C3%A9gale-le-maroc-adopte-officiellement-lheure-d%C3%A9t%C3%A9 +# http://www.infomediaire.ma/news/maroc/heure-légale-le-maroc-adopte-officiellement-lheure-dété # Governing Council adopted draft decree, that Morocco DST starts on # the last Sunday of March (March 25, 2012) and ends on # last Sunday of September (September 30, 2012) @@ -860,19 +870,28 @@ Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis # Friday or Saturday (and so the 2 days off are on a weekend), the next time # shift will be the next weekend. # -# From Paul Eggert (2020-05-31): +# From Milamber (2021-03-31, 2022-03-10): +# https://www.mmsp.gov.ma/fr/actualites.aspx?id=2076 +# https://www.ecoactu.ma/horaires-administration-ramadan-gmtheure-gmt-a-partir-de-dimanche-27-mars/ +# +# From Milamber (2023-03-14, 2023-03-15): +# The return to legal GMT time will take place this Sunday, March 19 at 3 a.m. +# ... the return to GMT+1 will be made on Sunday April 23, 2023 at 2 a.m. +# https://www.mmsp.gov.ma/fr/actualites/passage-à-l%E2%80%99heure-gmt-à-partir-du-dimanche-19-mars-2023 +# +# From Paul Eggert (2023-03-14): # For now, guess that in the future Morocco will fall back at 03:00 # the last Sunday before Ramadan, and spring forward at 02:00 the -# first Sunday after two days after Ramadan. To implement this, +# first Sunday after one day after Ramadan. To implement this, # transition dates and times for 2019 through 2087 were determined by -# running the following program under GNU Emacs 26.3. (This algorithm +# running the following program under GNU Emacs 28.2. (This algorithm # also produces the correct transition dates for 2016 through 2018, # though the times differ due to Morocco's time zone change in 2018.) # (let ((islamic-year 1440)) # (require 'cal-islam) # (while (< islamic-year 1511) # (let ((a (calendar-islamic-to-absolute (list 9 1 islamic-year))) -# (b (+ 2 (calendar-islamic-to-absolute (list 10 1 islamic-year)))) +# (b (+ 1 (calendar-islamic-to-absolute (list 10 1 islamic-year)))) # (sunday 0)) # (while (/= sunday (mod (setq a (1- a)) 7))) # (while (/= sunday (mod b 7)) @@ -886,10 +905,6 @@ Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis # (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a)) # (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b))))) # (setq islamic-year (+ 1 islamic-year)))) -# -# From Milamber (2021-03-31, 2022-03-10), confirming these predictions: -# https://www.mmsp.gov.ma/fr/actualites.aspx?id=2076 -# https://www.ecoactu.ma/horaires-administration-ramadan-gmtheure-gmt-a-partir-de-dimanche-27-mars/ # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Morocco 1939 only - Sep 12 0:00 1:00 - @@ -942,7 +957,7 @@ Rule Morocco 2021 only - May 16 2:00 0 - Rule Morocco 2022 only - Mar 27 3:00 -1:00 - Rule Morocco 2022 only - May 8 2:00 0 - Rule Morocco 2023 only - Mar 19 3:00 -1:00 - -Rule Morocco 2023 only - Apr 30 2:00 0 - +Rule Morocco 2023 only - Apr 23 2:00 0 - Rule Morocco 2024 only - Mar 10 3:00 -1:00 - Rule Morocco 2024 only - Apr 14 2:00 0 - Rule Morocco 2025 only - Feb 23 3:00 -1:00 - @@ -958,7 +973,7 @@ Rule Morocco 2029 only - Feb 18 2:00 0 - Rule Morocco 2029 only - Dec 30 3:00 -1:00 - Rule Morocco 2030 only - Feb 10 2:00 0 - Rule Morocco 2030 only - Dec 22 3:00 -1:00 - -Rule Morocco 2031 only - Feb 2 2:00 0 - +Rule Morocco 2031 only - Jan 26 2:00 0 - Rule Morocco 2031 only - Dec 14 3:00 -1:00 - Rule Morocco 2032 only - Jan 18 2:00 0 - Rule Morocco 2032 only - Nov 28 3:00 -1:00 - @@ -974,7 +989,7 @@ Rule Morocco 2036 only - Nov 23 2:00 0 - Rule Morocco 2037 only - Oct 4 3:00 -1:00 - Rule Morocco 2037 only - Nov 15 2:00 0 - Rule Morocco 2038 only - Sep 26 3:00 -1:00 - -Rule Morocco 2038 only - Nov 7 2:00 0 - +Rule Morocco 2038 only - Oct 31 2:00 0 - Rule Morocco 2039 only - Sep 18 3:00 -1:00 - Rule Morocco 2039 only - Oct 23 2:00 0 - Rule Morocco 2040 only - Sep 2 3:00 -1:00 - @@ -990,7 +1005,7 @@ Rule Morocco 2044 only - Aug 28 2:00 0 - Rule Morocco 2045 only - Jul 9 3:00 -1:00 - Rule Morocco 2045 only - Aug 20 2:00 0 - Rule Morocco 2046 only - Jul 1 3:00 -1:00 - -Rule Morocco 2046 only - Aug 12 2:00 0 - +Rule Morocco 2046 only - Aug 5 2:00 0 - Rule Morocco 2047 only - Jun 23 3:00 -1:00 - Rule Morocco 2047 only - Jul 28 2:00 0 - Rule Morocco 2048 only - Jun 7 3:00 -1:00 - @@ -1006,7 +1021,7 @@ Rule Morocco 2052 only - Jun 2 2:00 0 - Rule Morocco 2053 only - Apr 13 3:00 -1:00 - Rule Morocco 2053 only - May 25 2:00 0 - Rule Morocco 2054 only - Apr 5 3:00 -1:00 - -Rule Morocco 2054 only - May 17 2:00 0 - +Rule Morocco 2054 only - May 10 2:00 0 - Rule Morocco 2055 only - Mar 28 3:00 -1:00 - Rule Morocco 2055 only - May 2 2:00 0 - Rule Morocco 2056 only - Mar 12 3:00 -1:00 - @@ -1022,7 +1037,7 @@ Rule Morocco 2060 only - Mar 7 2:00 0 - Rule Morocco 2061 only - Jan 16 3:00 -1:00 - Rule Morocco 2061 only - Feb 27 2:00 0 - Rule Morocco 2062 only - Jan 8 3:00 -1:00 - -Rule Morocco 2062 only - Feb 19 2:00 0 - +Rule Morocco 2062 only - Feb 12 2:00 0 - Rule Morocco 2062 only - Dec 31 3:00 -1:00 - Rule Morocco 2063 only - Feb 4 2:00 0 - Rule Morocco 2063 only - Dec 16 3:00 -1:00 - @@ -1038,7 +1053,7 @@ Rule Morocco 2067 only - Dec 11 2:00 0 - Rule Morocco 2068 only - Oct 21 3:00 -1:00 - Rule Morocco 2068 only - Dec 2 2:00 0 - Rule Morocco 2069 only - Oct 13 3:00 -1:00 - -Rule Morocco 2069 only - Nov 24 2:00 0 - +Rule Morocco 2069 only - Nov 17 2:00 0 - Rule Morocco 2070 only - Oct 5 3:00 -1:00 - Rule Morocco 2070 only - Nov 9 2:00 0 - Rule Morocco 2071 only - Sep 20 3:00 -1:00 - @@ -1054,7 +1069,7 @@ Rule Morocco 2075 only - Sep 15 2:00 0 - Rule Morocco 2076 only - Jul 26 3:00 -1:00 - Rule Morocco 2076 only - Sep 6 2:00 0 - Rule Morocco 2077 only - Jul 18 3:00 -1:00 - -Rule Morocco 2077 only - Aug 29 2:00 0 - +Rule Morocco 2077 only - Aug 22 2:00 0 - Rule Morocco 2078 only - Jul 10 3:00 -1:00 - Rule Morocco 2078 only - Aug 14 2:00 0 - Rule Morocco 2079 only - Jun 25 3:00 -1:00 - @@ -1064,13 +1079,13 @@ Rule Morocco 2080 only - Jul 21 2:00 0 - Rule Morocco 2081 only - Jun 1 3:00 -1:00 - Rule Morocco 2081 only - Jul 13 2:00 0 - Rule Morocco 2082 only - May 24 3:00 -1:00 - -Rule Morocco 2082 only - Jul 5 2:00 0 - +Rule Morocco 2082 only - Jun 28 2:00 0 - Rule Morocco 2083 only - May 16 3:00 -1:00 - Rule Morocco 2083 only - Jun 20 2:00 0 - Rule Morocco 2084 only - Apr 30 3:00 -1:00 - Rule Morocco 2084 only - Jun 11 2:00 0 - Rule Morocco 2085 only - Apr 22 3:00 -1:00 - -Rule Morocco 2085 only - Jun 3 2:00 0 - +Rule Morocco 2085 only - May 27 2:00 0 - Rule Morocco 2086 only - Apr 14 3:00 -1:00 - Rule Morocco 2086 only - May 19 2:00 0 - Rule Morocco 2087 only - Mar 30 3:00 -1:00 - @@ -1213,15 +1228,15 @@ Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8 # From P Chan (2020-12-03): # GMT was adopted as the standard time of Lagos on 1905-07-01. # Lagos Weekly Record, 1905-06-24, p 3 -# http://ddsnext.crl.edu/titles/31558#?c=0&m=668&s=0&cv=2&r=0&xywh=1446%2C5221%2C1931%2C1235 +# http://ddsnext.crl.edu/titles/31558#?c=0&m=668&s=0&cv=2&r=0&xywh=1446,5221,1931,1235 # says "It is officially notified that on and after the 1st of July 1905 -# Greenwich Mean Solar Time will be adopted thought the Colony and +# Greenwich Mean Solar Time will be adopted throughout the Colony and # Protectorate, and that it will be necessary to put all clocks 13 minutes and # 35 seconds back, recording local mean time." # # It seemed that Lagos returned to LMT on 1908-07-01. # [The Lagos Standard], 1908-07-01, p 5 -# http://ddsnext.crl.edu/titles/31556#?c=0&m=78&s=0&cv=4&r=0&xywh=-92%2C3590%2C3944%2C2523 +# http://ddsnext.crl.edu/titles/31556#?c=0&m=78&s=0&cv=4&r=0&xywh=-92,3590,3944,2523 # says "Scarcely have the people become accustomed to this new time, when # another official notice has now appeared announcing that from and after the # 1st July next, return will be made to local mean time." @@ -1233,7 +1248,7 @@ Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8 # https://libsysdigi.library.illinois.edu/ilharvest/Africana/Books2011-05/3064634/3064634_1914/3064634_1914_opt.pdf#page=27 # "On January 1st [1914], a universal standard time for Nigeria was adopted, # viz., half an hour fast on Greenwich mean time, corresponding to the meridian -# 7 [degrees] 30' E. long." +# 7° 30' E. long." # Lloyd's Register of Shipping (1915) says "Hitherto the time observed in Lagos # was the local mean time. On 1st January, 1914, standard time for the whole of # Nigeria was introduced ... Lagos time has been advanced about 16 minutes @@ -1251,7 +1266,7 @@ Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8 # The Lagos Weekly Record, 1919-09-20, p 3 details discussion on the first # reading of this Bill by the Legislative Council of the Colony of Nigeria on # Thursday 1919-08-28: -# http://ddsnext.crl.edu/titles/31558?terms&item_id=303484#?m=1118&c=1&s=0&cv=2&r=0&xywh=1261%2C3408%2C2994%2C1915 +# http://ddsnext.crl.edu/titles/31558?terms&item_id=303484#?m=1118&c=1&s=0&cv=2&r=0&xywh=1261,3408,2994,1915 # "The proposal is that the Globe should be divided into twelve zones East and # West of Greenwich, of one hour each, Nigeria falling into the zone with a # standard of one hour fast on Greenwich Mean Time. Nigeria standard time is diff --git a/make/data/tzdata/antarctica b/make/data/tzdata/antarctica index 792542b9224..3de5e726eb4 100644 --- a/make/data/tzdata/antarctica +++ b/make/data/tzdata/antarctica @@ -315,7 +315,7 @@ Zone Antarctica/Rothera 0 - -00 1976 Dec 1 # but that he found it more convenient to keep GMT+12 # as supplies for the station were coming from McMurdo Sound, # which was on GMT+12 because New Zealand was on GMT+12 all year -# at that time (1957). (Source: Siple's book 90 Degrees South.) +# at that time (1957). (Source: Siple's book 90° South.) # # From Susan Smith # http://www.cybertours.com/whs/pole10.html diff --git a/make/data/tzdata/asia b/make/data/tzdata/asia index ff81978bc47..6a048c3ad28 100644 --- a/make/data/tzdata/asia +++ b/make/data/tzdata/asia @@ -2714,6 +2714,40 @@ Zone Asia/Pyongyang 8:23:00 - LMT 1908 Apr 1 # Lebanon +# +# From Saadallah Itani (2023-03-23): +# Lebanon ... announced today delay of Spring forward from March 25 to April 20. +# +# From Paul Eggert (2023-03-27): +# This announcement was by the Lebanese caretaker prime minister Najib Mikati. +# https://www.mtv.com.lb/en/News/Local/1352516/lebanon-postpones-daylight-saving-time-adoption +# A video was later leaked to the media of parliament speaker Nabih Berri +# asking Mikati to postpone DST to aid observance of Ramadan, Mikati objecting +# that this would cause problems such as scheduling airline flights, to which +# Berri interjected, "What flights?" +# +# The change was controversial and led to a partly-sectarian divide. +# Many Lebanese institutions, including the education ministry, the Maronite +# church, and two news channels LCBI and MTV, ignored the announcement and +# went ahead with the long-scheduled spring-forward on March 25/26, some +# arguing that the prime minister had not followed the law because the change +# had not been approved by the cabinet. Google went with the announcement; +# Apple ignored it. At least one bank followed the announcement for its doors, +# but ignored the announcement in internal computer systems. +# Beirut international airport listed two times for each departure. +# Dan Azzi wrote "My view is that this whole thing is a Dumb and Dumber movie." +# Eventually the prime minister backed down, said the cabinet had decided to +# stick with its 1998 decision, and that DST would begin midnight March 29/30. +# https://www.nna-leb.gov.lb/en/miscellaneous/604093/lebanon-has-two-times-of-day-amid-daylight-savings +# https://www.cnbc.com/2023/03/27/lebanon-in-two-different-time-zones-as-government-disagrees-on-daylight-savings.html +# +# Although we could model the chaos with two Zones, that would likely cause +# more trouble than it would cure. Since so many manual clocks and +# computer-based timestamps ignored the announcement, stick with official +# cabinet resolutions in the data while recording the prime minister's +# announcement as a comment. This is how we treated a similar situation in +# Rio de Janeiro in spring 1993. +# # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Lebanon 1920 only - Mar 28 0:00 1:00 S Rule Lebanon 1920 only - Oct 25 0:00 0 - @@ -2739,6 +2773,10 @@ Rule Lebanon 1992 only - Oct 4 0:00 0 - Rule Lebanon 1993 max - Mar lastSun 0:00 1:00 S Rule Lebanon 1993 1998 - Sep lastSun 0:00 0 - Rule Lebanon 1999 max - Oct lastSun 0:00 0 - +# This one-time rule, announced by the prime minister first for April 21 +# then for March 30, is commented out for reasons described above. +#Rule Lebanon 2023 only - Mar 30 0:00 1:00 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Beirut 2:22:00 - LMT 1880 2:00 Lebanon EE%sT @@ -2977,7 +3015,7 @@ Zone Asia/Kathmandu 5:41:16 - LMT 1920 # 9pm and moving clocks forward by one hour for the next three months. ...." # # http://www.worldtimezone.com/dst_news/dst_news_pakistan01.html -# http://www.dailytimes.com.pk/default.asp?page=2008%5C05%5C15%5Cstory_15-5-2008_pg1_4 +# http://www.dailytimes.com.pk/default.asp?page=2008\05\15\story_15-5-2008_pg1_4 # From Arthur David Olson (2008-05-19): # XXX--midnight transitions is a guess; 2008 only is a guess. @@ -3300,7 +3338,7 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # Some of many sources in Arabic: # http://www.samanews.com/index.php?act=Show&id=122638 # -# http://safa.ps/details/news/74352/%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%AA%D9%88%D9%82%D9%8A%D8%AA-%D8%A7%D9%84%D8%B5%D9%8A%D9%81%D9%8A-%D8%A8%D8%A7%D9%84%D8%B6%D9%81%D8%A9-%D9%88%D8%BA%D8%B2%D8%A9-%D9%84%D9%8A%D9%84%D8%A9-%D8%A7%D9%84%D8%AC%D9%85%D8%B9%D8%A9.html +# http://safa.ps/details/news/74352/بدء-التوقيت-الصيفي-بالضفة-وغزة-ليلة-الجمعة.html # # Our brief summary: # https://www.timeanddate.com/news/time/gaza-west-bank-dst-2012.html @@ -3310,7 +3348,7 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # time from midnight on Friday, March 29, 2013" (translated). # [These are in Arabic and are for Gaza and for Ramallah, respectively.] # http://www.samanews.com/index.php?act=Show&id=154120 -# http://safa.ps/details/news/99844/%D8%B1%D8%A7%D9%85-%D8%A7%D9%84%D9%84%D9%87-%D8%A8%D8%AF%D8%A1-%D8%A7%D9%84%D8%AA%D9%88%D9%82%D9%8A%D8%AA-%D8%A7%D9%84%D8%B5%D9%8A%D9%81%D9%8A-29-%D8%A7%D9%84%D8%AC%D8%A7%D8%B1%D9%8A.html +# http://safa.ps/details/news/99844/رام-الله-بدء-التوقيت-الصيفي-29-الجاري.html # From Steffen Thorsen (2013-09-24): # The Gaza and West Bank are ending DST Thursday at midnight @@ -3408,9 +3446,41 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 # (2022-08-31): ... the Saturday before the last Sunday in March and October # at 2:00 AM ,for the years from 2023 to 2026. # (2022-09-05): https://mtit.pna.ps/Site/New/1453 -# -# From Paul Eggert (2022-08-31): -# For now, assume that this rule will also be used after 2026. + +# From Heba Hamad (2023-03-22): +# ... summer time will begin in Palestine from Saturday 04-29-2023, +# 02:00 AM by 60 minutes forward. +# +# From Paul Eggert (2023-03-22): +# For now, guess that spring and fall transitions will normally +# continue to use 2022's rules, that during DST Palestine will switch +# to standard time at 02:00 the last Saturday before Ramadan and back +# to DST at 02:00 the first Saturday after Ramadan, and that +# if the normal spring-forward or fall-back transition occurs during +# Ramadan the former is delayed and the latter advanced. +# To implement this, I predicted Ramadan-oriented transition dates for +# 2023 through 2086 by running the following program under GNU Emacs 28.2, +# with the results integrated by hand into the table below. +# Predictions after 2086 are approximated without Ramadan. +# +# (let ((islamic-year 1444)) +# (require 'cal-islam) +# (while (< islamic-year 1510) +# (let ((a (calendar-islamic-to-absolute (list 9 1 islamic-year))) +# (b (+ 1 (calendar-islamic-to-absolute (list 10 1 islamic-year)))) +# (saturday 6)) +# (while (/= saturday (mod (setq a (1- a)) 7))) +# (while (/= saturday (mod b 7)) +# (setq b (1+ b))) +# (setq a (calendar-gregorian-from-absolute a)) +# (setq b (calendar-gregorian-from-absolute b)) +# (insert +# (format +# (concat "Rule Palestine\t%d\tonly\t-\t%s\t%2d\t2:00\t0\t-\n" +# "Rule Palestine\t%d\tonly\t-\t%s\t%2d\t2:00\t1:00\tS\n") +# (car (cdr (cdr a))) (calendar-month-name (car a) t) (car (cdr a)) +# (car (cdr (cdr b))) (calendar-month-name (car b) t) (car (cdr b))))) +# (setq islamic-year (+ 1 islamic-year)))) # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule EgyptAsia 1957 only - May 10 0:00 1:00 S @@ -3450,8 +3520,86 @@ Rule Palestine 2020 2021 - Mar Sat<=30 0:00 1:00 S Rule Palestine 2020 only - Oct 24 1:00 0 - Rule Palestine 2021 only - Oct 29 1:00 0 - Rule Palestine 2022 only - Mar 27 0:00 1:00 S -Rule Palestine 2022 max - Oct Sat<=30 2:00 0 - -Rule Palestine 2023 max - Mar Sat<=30 2:00 1:00 S +Rule Palestine 2022 2035 - Oct Sat<=30 2:00 0 - +Rule Palestine 2023 only - Apr 29 2:00 1:00 S +Rule Palestine 2024 only - Apr 13 2:00 1:00 S +Rule Palestine 2025 only - Apr 5 2:00 1:00 S +Rule Palestine 2026 2054 - Mar Sat<=30 2:00 1:00 S +Rule Palestine 2036 only - Oct 18 2:00 0 - +Rule Palestine 2037 only - Oct 10 2:00 0 - +Rule Palestine 2038 only - Sep 25 2:00 0 - +Rule Palestine 2039 only - Sep 17 2:00 0 - +Rule Palestine 2039 only - Oct 22 2:00 1:00 S +Rule Palestine 2039 2067 - Oct Sat<=30 2:00 0 - +Rule Palestine 2040 only - Sep 1 2:00 0 - +Rule Palestine 2040 only - Oct 13 2:00 1:00 S +Rule Palestine 2041 only - Aug 24 2:00 0 - +Rule Palestine 2041 only - Sep 28 2:00 1:00 S +Rule Palestine 2042 only - Aug 16 2:00 0 - +Rule Palestine 2042 only - Sep 20 2:00 1:00 S +Rule Palestine 2043 only - Aug 1 2:00 0 - +Rule Palestine 2043 only - Sep 12 2:00 1:00 S +Rule Palestine 2044 only - Jul 23 2:00 0 - +Rule Palestine 2044 only - Aug 27 2:00 1:00 S +Rule Palestine 2045 only - Jul 15 2:00 0 - +Rule Palestine 2045 only - Aug 19 2:00 1:00 S +Rule Palestine 2046 only - Jun 30 2:00 0 - +Rule Palestine 2046 only - Aug 11 2:00 1:00 S +Rule Palestine 2047 only - Jun 22 2:00 0 - +Rule Palestine 2047 only - Jul 27 2:00 1:00 S +Rule Palestine 2048 only - Jun 6 2:00 0 - +Rule Palestine 2048 only - Jul 18 2:00 1:00 S +Rule Palestine 2049 only - May 29 2:00 0 - +Rule Palestine 2049 only - Jul 3 2:00 1:00 S +Rule Palestine 2050 only - May 21 2:00 0 - +Rule Palestine 2050 only - Jun 25 2:00 1:00 S +Rule Palestine 2051 only - May 6 2:00 0 - +Rule Palestine 2051 only - Jun 17 2:00 1:00 S +Rule Palestine 2052 only - Apr 27 2:00 0 - +Rule Palestine 2052 only - Jun 1 2:00 1:00 S +Rule Palestine 2053 only - Apr 12 2:00 0 - +Rule Palestine 2053 only - May 24 2:00 1:00 S +Rule Palestine 2054 only - Apr 4 2:00 0 - +Rule Palestine 2054 only - May 16 2:00 1:00 S +Rule Palestine 2055 only - May 1 2:00 1:00 S +Rule Palestine 2056 only - Apr 22 2:00 1:00 S +Rule Palestine 2057 only - Apr 7 2:00 1:00 S +Rule Palestine 2058 max - Mar Sat<=30 2:00 1:00 S +Rule Palestine 2068 only - Oct 20 2:00 0 - +Rule Palestine 2069 only - Oct 12 2:00 0 - +Rule Palestine 2070 only - Oct 4 2:00 0 - +Rule Palestine 2071 only - Sep 19 2:00 0 - +Rule Palestine 2072 only - Sep 10 2:00 0 - +Rule Palestine 2072 only - Oct 15 2:00 1:00 S +Rule Palestine 2073 only - Sep 2 2:00 0 - +Rule Palestine 2073 only - Oct 7 2:00 1:00 S +Rule Palestine 2074 only - Aug 18 2:00 0 - +Rule Palestine 2074 only - Sep 29 2:00 1:00 S +Rule Palestine 2075 only - Aug 10 2:00 0 - +Rule Palestine 2075 only - Sep 14 2:00 1:00 S +Rule Palestine 2075 max - Oct Sat<=30 2:00 0 - +Rule Palestine 2076 only - Jul 25 2:00 0 - +Rule Palestine 2076 only - Sep 5 2:00 1:00 S +Rule Palestine 2077 only - Jul 17 2:00 0 - +Rule Palestine 2077 only - Aug 28 2:00 1:00 S +Rule Palestine 2078 only - Jul 9 2:00 0 - +Rule Palestine 2078 only - Aug 13 2:00 1:00 S +Rule Palestine 2079 only - Jun 24 2:00 0 - +Rule Palestine 2079 only - Aug 5 2:00 1:00 S +Rule Palestine 2080 only - Jun 15 2:00 0 - +Rule Palestine 2080 only - Jul 20 2:00 1:00 S +Rule Palestine 2081 only - Jun 7 2:00 0 - +Rule Palestine 2081 only - Jul 12 2:00 1:00 S +Rule Palestine 2082 only - May 23 2:00 0 - +Rule Palestine 2082 only - Jul 4 2:00 1:00 S +Rule Palestine 2083 only - May 15 2:00 0 - +Rule Palestine 2083 only - Jun 19 2:00 1:00 S +Rule Palestine 2084 only - Apr 29 2:00 0 - +Rule Palestine 2084 only - Jun 10 2:00 1:00 S +Rule Palestine 2085 only - Apr 21 2:00 0 - +Rule Palestine 2085 only - Jun 2 2:00 1:00 S +Rule Palestine 2086 only - Apr 13 2:00 0 - +Rule Palestine 2086 only - May 18 2:00 1:00 S # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone Asia/Gaza 2:17:52 - LMT 1900 Oct @@ -3655,7 +3803,7 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 # standard time is SLST. # # From Paul Eggert (2016-10-18): -# "SLST" seems to be reasonably recent and rarely-used outside time +# "SLST" seems to be reasonably recent and rarely used outside time # zone nerd sources. I searched Google News and found three uses of # it in the International Business Times of India in February and # March of this year when discussing cricket match times, but nothing diff --git a/make/data/tzdata/australasia b/make/data/tzdata/australasia index fbe3b8a6d72..893d7055eab 100644 --- a/make/data/tzdata/australasia +++ b/make/data/tzdata/australasia @@ -346,7 +346,7 @@ Zone Antarctica/Macquarie 0 - -00 1899 Nov # From Steffen Thorsen (2013-01-10): # Fiji will end DST on 2014-01-19 02:00: -# http://www.fiji.gov.fj/Media-Center/Press-Releases/DAYLIGHT-SAVINGS-TO-END-THIS-MONTH-%281%29.aspx +# http://www.fiji.gov.fj/Media-Center/Press-Releases/DAYLIGHT-SAVINGS-TO-END-THIS-MONTH-(1).aspx # From Ken Rylander (2014-10-20): # DST will start Nov. 2 this year. @@ -746,7 +746,7 @@ Zone Pacific/Pago_Pago 12:37:12 - LMT 1892 Jul 5 # # Samoa's Daylight Saving Time Act 2009 is available here, but does not # contain any dates: -# http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20%28English%29%20-%20Final%207-7-091.pdf +# http://www.parliament.gov.ws/documents/acts/Daylight%20Saving%20Act%20%202009%20(English)%20-%20Final%207-7-091.pdf # From Laupue Raymond Hughes (2010-10-07): # Please see @@ -1831,7 +1831,7 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila # period. It would probably be reasonable to assume Guam use GMT+9 during # that period of time like the surrounding area. -# From Paul Eggert (2018-11-18): +# From Paul Eggert (2023-01-23): # Howse writes (p 153) "The Spaniards, on the other hand, reached the # Philippines and the Ladrones from America," and implies that the Ladrones # (now called the Marianas) kept American date for quite some time. @@ -1844,7 +1844,7 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila # they did as that avoids the need for a separate zone due to our 1970 cutoff. # # US Public Law 106-564 (2000-12-23) made UT +10 the official standard time, -# under the name "Chamorro Standard Time". There is no official abbreviation, +# under the name "Chamorro standard time". There is no official abbreviation, # but Congressman Robert A. Underwood, author of the bill that became law, # wrote in a press release (2000-12-27) that he will seek the use of "ChST". @@ -2222,24 +2222,18 @@ Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila # an international standard, there are some places on the high seas where the # correct date is ambiguous. -# From Wikipedia (2005-08-31): -# Before 1920, all ships kept local apparent time on the high seas by setting -# their clocks at night or at the morning sight so that, given the ship's -# speed and direction, it would be 12 o'clock when the Sun crossed the ship's -# meridian (12 o'clock = local apparent noon). During 1917, at the -# Anglo-French Conference on Time-keeping at Sea, it was recommended that all -# ships, both military and civilian, should adopt hourly standard time zones -# on the high seas. Whenever a ship was within the territorial waters of any -# nation it would use that nation's standard time. The captain was permitted -# to change his ship's clocks at a time of his choice following his ship's -# entry into another zone time - he often chose midnight. These zones were -# adopted by all major fleets between 1920 and 1925 but not by many -# independent merchant ships until World War II. - -# From Paul Eggert, using references suggested by Oscar van Vlijmen -# (2005-03-20): -# -# The American Practical Navigator (2002) -# http://pollux.nss.nima.mil/pubs/pubs_j_apn_sections.html?rid=187 -# talks only about the 180-degree meridian with respect to ships in -# international waters; it ignores the international date line. +# From Wikipedia (2023-01-23): +# The nautical time zone system is analogous to the terrestrial time zone +# system for use on high seas. Under the system time changes are required for +# changes of longitude in one-hour steps. The one-hour step corresponds to a +# time zone width of 15° longitude. The 15° gore that is offset from GMT or +# UT1 (not UTC) by twelve hours is bisected by the nautical date line into two +# 7°30' gores that differ from GMT by ±12 hours. A nautical date line is +# implied but not explicitly drawn on time zone maps. It follows the 180th +# meridian except where it is interrupted by territorial waters adjacent to +# land, forming gaps: it is a pole-to-pole dashed line. + +# From Paul Eggert (2023-01-23): +# The American Practical Navigator , +# 2019 edition, merely says that the International Date Line +# "coincides with the 180th meridian over most of its length." diff --git a/make/data/tzdata/backward b/make/data/tzdata/backward index fa44f655009..c0746d6dd1b 100644 --- a/make/data/tzdata/backward +++ b/make/data/tzdata/backward @@ -297,6 +297,7 @@ Link America/Argentina/Cordoba America/Rosario Link America/Tijuana America/Santa_Isabel Link America/Denver America/Shiprock Link America/Toronto America/Thunder_Bay +Link America/Edmonton America/Yellowknife Link Pacific/Auckland Antarctica/South_Pole Link Asia/Shanghai Asia/Chongqing Link Asia/Shanghai Asia/Harbin diff --git a/make/data/tzdata/europe b/make/data/tzdata/europe index acc5da3ec79..446d2e1e658 100644 --- a/make/data/tzdata/europe +++ b/make/data/tzdata/europe @@ -540,9 +540,7 @@ Zone Europe/London -0:01:15 - LMT 1847 Dec 1 # other form with a traditional approximation for Irish timestamps # after 1971-10-31 02:00 UTC; although this approximation has tm_isdst # flags that are reversed, its UTC offsets are correct and this often -# suffices. This source file currently uses only nonnegative SAVE -# values, but this is intended to change and downstream code should -# not rely on it. +# suffices.... # # The following is like GB-Eire and EU, except with standard time in # summer and negative daylight saving time in winter. It is for when @@ -1136,19 +1134,18 @@ Zone Atlantic/Faroe -0:27:04 - LMT 1908 Jan 11 # Tórshavn # # From Jürgen Appel (2022-11-25): # https://ina.gl/samlinger/oversigt-over-samlinger/samling/dagsordener/dagsorden.aspx?lang=da&day=24-11-2022 -# If I understand this correctly, from the next planned switch to -# summer time, Greenland will permanently stay at that time, i.e. no -# switch back to winter time in 2023 will occur. -# -# From Paul Eggert (2022-11-28): -# The official document in Danish -# https://naalakkersuisut.gl/-/media/naalakkersuisut/filer/kundgoerelser/2022/11/2511/31_da_inatsisartutlov-om-tidens-bestemmelse.pdf?la=da&hash=A33597D8A38CC7038465241119EF34F3 -# says standard time for Greenland is -02, that Naalakkersuisut can lay down -# rules for DST and can require some areas to use a different time zone, -# and that this all takes effect 2023-03-25 22:00. The abovementioned -# "bekymringer" URL says the intent is no transition March 25, that -# Greenland will not go back to winter time in fall 2023, and that -# only America/Nuuk is affected (though further changes may occur). +# +# From Thomas M. Steenholdt (2022-12-02): +# - The bill to move America/Nuuk from UTC-03 to UTC-02 passed. +# - The bill to stop observing DST did not (Greenland will stop observing DST +# when EU does). +# Details on the implementation are here (section 6): +# https://ina.gl/dvd/EM%202022/pdf/media/2553529/pkt17_em2022_tidens_bestemmelse_bem_da.pdf +# This is how the change will be implemented: +# 1. The shift *to* DST in 2023 happens as normal. +# 2. The shift *from* DST in 2023 happens as normal, but coincides with the +# shift to UTC-02 normaltime (people will not change their clocks here). +# 3. After this, DST is still observed, but as -02/-01 instead of -03/-02. # Rule NAME FROM TO - IN ON AT SAVE LETTER/S Rule Thule 1991 1992 - Mar lastSun 2:00 1:00 D @@ -1172,8 +1169,8 @@ Zone America/Scoresbysund -1:27:52 - LMT 1916 Jul 28 # Ittoqqortoormiit -1:00 EU -01/+00 Zone America/Nuuk -3:26:56 - LMT 1916 Jul 28 # Godthåb -3:00 - -03 1980 Apr 6 2:00 - -3:00 EU -03/-02 2023 Mar 25 22:00 - -2:00 - -02 + -3:00 EU -03/-02 2023 Oct 29 1:00u + -2:00 EU -02/-01 Zone America/Thule -4:35:08 - LMT 1916 Jul 28 # Pituffik -4:00 Thule A%sT @@ -1509,9 +1506,9 @@ Zone Europe/Paris 0:09:21 - LMT 1891 Mar 16 Rule Germany 1946 only - Apr 14 2:00s 1:00 S Rule Germany 1946 only - Oct 7 2:00s 0 - Rule Germany 1947 1949 - Oct Sun>=1 2:00s 0 - -# http://www.ptb.de/de/org/4/44/441/salt.htm says the following transition -# occurred at 3:00 MEZ, not the 2:00 MEZ given in Shanks & Pottenger. -# Go with the PTB. +# https://www.ptb.de/cms/en/ptb/fachabteilungen/abt4/fb-44/ag-441/realisation-of-legal-time-in-germany/dst-and-midsummer-dst-in-germany-until-1979.html +# says the following transition occurred at 3:00 MEZ, not the 2:00 MEZ +# given in Shanks & Pottenger. Go with the PTB. Rule Germany 1947 only - Apr 6 3:00s 1:00 S Rule Germany 1947 only - May 11 2:00s 2:00 M Rule Germany 1947 only - Jun 29 3:00 1:00 S @@ -2272,7 +2269,7 @@ Zone Europe/Bucharest 1:44:24 - LMT 1891 Oct # the State Duma has approved ... the draft bill on returning to # winter time standard and return Russia 11 time zones. The new # regulations will come into effect on October 26, 2014 at 02:00 ... -# http://asozd2.duma.gov.ru/main.nsf/%28Spravka%29?OpenAgent&RN=431985-6&02 +# http://asozd2.duma.gov.ru/main.nsf/(Spravka)?OpenAgent&RN=431985-6&02 # Here is a link where we put together table (based on approved Bill N # 431985-6) with proposed 11 Russian time zones and corresponding # areas/cities/administrative centers in the Russian Federation (in English): @@ -2682,13 +2679,13 @@ Zone Europe/Volgograd 2:57:40 - LMT 1920 Jan 3 3:00 - +03 1930 Jun 21 4:00 - +04 1961 Nov 11 4:00 Russia +04/+05 1988 Mar 27 2:00s - 3:00 Russia +03/+04 1991 Mar 31 2:00s + 3:00 Russia MSK/MSD 1991 Mar 31 2:00s 4:00 - +04 1992 Mar 29 2:00s - 3:00 Russia +03/+04 2011 Mar 27 2:00s - 4:00 - +04 2014 Oct 26 2:00s - 3:00 - +03 2018 Oct 28 2:00s + 3:00 Russia MSK/MSD 2011 Mar 27 2:00s + 4:00 - MSK 2014 Oct 26 2:00s + 3:00 - MSK 2018 Oct 28 2:00s 4:00 - +04 2020 Dec 27 2:00s - 3:00 - +03 + 3:00 - MSK # From Paul Eggert (2016-11-11): # Europe/Saratov covers: @@ -2719,11 +2716,11 @@ Zone Europe/Saratov 3:04:18 - LMT 1919 Jul 1 0:00u Zone Europe/Kirov 3:18:48 - LMT 1919 Jul 1 0:00u 3:00 - +03 1930 Jun 21 4:00 Russia +04/+05 1989 Mar 26 2:00s - 3:00 Russia +03/+04 1991 Mar 31 2:00s + 3:00 Russia MSK/MSD 1991 Mar 31 2:00s 4:00 - +04 1992 Mar 29 2:00s - 3:00 Russia +03/+04 2011 Mar 27 2:00s - 4:00 - +04 2014 Oct 26 2:00s - 3:00 - +03 + 3:00 Russia MSK/MSD 2011 Mar 27 2:00s + 4:00 - MSK 2014 Oct 26 2:00s + 3:00 - MSK # From Tim Parenti (2014-07-03), per Oscar van Vlijmen (2001-08-25): # Europe/Samara covers... diff --git a/make/data/tzdata/iso3166.tab b/make/data/tzdata/iso3166.tab index fbfb74bec45..cea17732dd1 100644 --- a/make/data/tzdata/iso3166.tab +++ b/make/data/tzdata/iso3166.tab @@ -261,7 +261,7 @@ SY Syria SZ Eswatini (Swaziland) TC Turks & Caicos Is TD Chad -TF French Southern Territories +TF French S. Terr. TG Togo TH Thailand TJ Tajikistan diff --git a/make/data/tzdata/leapseconds b/make/data/tzdata/leapseconds index d6fb840f512..89ce8b89cd2 100644 --- a/make/data/tzdata/leapseconds +++ b/make/data/tzdata/leapseconds @@ -95,11 +95,11 @@ Leap 2016 Dec 31 23:59:60 + S # Any additional leap seconds will come after this. # This Expires line is commented out for now, # so that pre-2020a zic implementations do not reject this file. -#Expires 2023 Jun 28 00:00:00 +#Expires 2023 Dec 28 00:00:00 # POSIX timestamps for the data in this file: #updated 1467936000 (2016-07-08 00:00:00 UTC) -#expires 1687910400 (2023-06-28 00:00:00 UTC) +#expires 1703721600 (2023-12-28 00:00:00 UTC) -# Updated through IERS Bulletin C64 -# File expires on: 28 June 2023 +# Updated through IERS Bulletin C65 +# File expires on: 28 December 2023 diff --git a/make/data/tzdata/northamerica b/make/data/tzdata/northamerica index a5fd701f88c..e240cf35103 100644 --- a/make/data/tzdata/northamerica +++ b/make/data/tzdata/northamerica @@ -1,4 +1,3 @@ -# # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -299,9 +298,10 @@ Zone PST8PDT -8:00 US P%sT # -10 Standard Alaska Time (AST) Alaska-Hawaii standard time (AHST) # -11 (unofficial) Nome (NST) Bering standard time (BST) # -# From Paul Eggert (2000-01-08), following a heads-up from Rives McDow: -# Public law 106-564 (2000-12-23) introduced ... "Chamorro Standard Time" +# From Paul Eggert (2023-01-23), from a 2001-01-08 heads-up from Rives McDow: +# Public law 106-564 (2000-12-23) introduced "Chamorro standard time" # for time in Guam and the Northern Marianas. See the file "australasia". +# Also see 15 U.S.C. §263 . # # From Paul Eggert (2015-04-17): # HST and HDT are standardized abbreviations for Hawaii-Aleutian @@ -618,7 +618,7 @@ Zone America/Los_Angeles -7:52:58 - LMT 1883 Nov 18 20:00u # local times of other Alaskan locations so that they change simultaneously. # From Paul Eggert (2014-07-18): -# One opinion of the early-1980s turmoil in Alaska over time zones and +# One opinion of the early 1980s turmoil in Alaska over time zones and # daylight saving time appeared as graffiti on a Juneau airport wall: # "Welcome to Juneau. Please turn your watch back to the 19th century." # See: Turner W. Alaska's four time zones now two. NY Times 1983-11-01. @@ -690,6 +690,10 @@ Zone America/Los_Angeles -7:52:58 - LMT 1883 Nov 18 20:00u # So they won't be waiting for Alaska to join them on 2019-03-10, but will # rather change their clocks twice in seven weeks. +# From Paul Eggert (2023-01-23): +# America/Adak is for the Aleutian Islands that are part of Alaska +# and are west of 169.5° W. + # Zone NAME STDOFF RULES FORMAT [UNTIL] Zone America/Juneau 15:02:19 - LMT 1867 Oct 19 15:33:32 -8:57:41 - LMT 1900 Aug 20 12:00 @@ -2148,10 +2152,6 @@ Zone America/Fort_Nelson -8:10:47 - LMT 1884 # Nunavut ... moved ... to incorporate the whole territory into one time zone. # Nunavut moves to single time zone Oct. 31 # http://www.nunatsiaq.com/nunavut/nvt90903_13.html -# -# From Antoine Leca (1999-09-06): -# We then need to create a new timezone for the Kitikmeot region of Nunavut -# to differentiate it from the Yellowknife region. # From Paul Eggert (1999-09-20): # Basic Facts: The New Territory @@ -2345,9 +2345,6 @@ Zone America/Cambridge_Bay 0 - -00 1920 # trading post est.? -5:00 - EST 2000 Nov 5 0:00 -6:00 - CST 2001 Apr 1 3:00 -7:00 Canada M%sT -Zone America/Yellowknife 0 - -00 1935 # Yellowknife founded? - -7:00 NT_YK M%sT 1980 - -7:00 Canada M%sT Zone America/Inuvik 0 - -00 1953 # Inuvik founded -8:00 NT_YK P%sT 1979 Apr lastSun 2:00 -7:00 NT_YK M%sT 1980 @@ -2584,7 +2581,7 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 # and in addition changes all of Chihuahua to -06 with no DST. # From Heitor David Pinto (2022-11-28): -# Now the northern municipalities want to have the same time zone as the +# Now the northern [municipios] want to have the same time zone as the # respective neighboring cities in the US, for example Juárez in UTC-7 with # DST, matching El Paso, and Ojinaga in UTC-6 with DST, matching Presidio.... # the president authorized the publication of the decree for November 29, @@ -2621,7 +2618,7 @@ Zone America/Merida -5:58:28 - LMT 1922 Jan 1 6:00u -5:00 - EST 1982 Dec 2 -6:00 Mexico C%sT # Coahuila, Nuevo León, Tamaulipas (near US border) -# This includes the following municipalities: +# This includes the following municipios: # in Coahuila: Acuña, Allende, Guerrero, Hidalgo, Jiménez, Morelos, Nava, # Ocampo, Piedras Negras, Villa Unión, Zaragoza # in Nuevo León: Anáhuac @@ -2647,8 +2644,8 @@ Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u -6:00 - CST 2002 Feb 20 -6:00 Mexico C%sT # Chihuahua (near US border - western side) -# This includes the municipalities of Janos, Ascensión, Juárez, Guadalupe, -# and Práxedis G Guerrero. +# This includes the municipios of Janos, Ascensión, Juárez, Guadalupe, and +# Práxedis G Guerrero. # http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u -7:00 - MST 1927 Jun 10 23:00 @@ -2662,7 +2659,8 @@ Zone America/Ciudad_Juarez -7:05:56 - LMT 1922 Jan 1 7:00u -6:00 - CST 2022 Nov 30 0:00 -7:00 US M%sT # Chihuahua (near US border - eastern side) -# The municipalities of Coyame del Sotol, Ojinaga, and Manuel Benavides. +# This includes the municipios of Coyame del Sotol, Ojinaga, and Manuel +# Benavides. # http://gaceta.diputados.gob.mx/PDF/65/2a022/nov/20221124-VII.pdf Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u -7:00 - MST 1927 Jun 10 23:00 @@ -3083,7 +3081,7 @@ Zone America/Costa_Rica -5:36:13 - LMT 1890 # San José # # He supplied these references: # -# http://www.prensalatina.com.mx/article.asp?ID=%7B4CC32C1B-A9F7-42FB-8A07-8631AFC923AF%7D&language=ES +# http://www.prensalatina.com.mx/article.asp?ID={4CC32C1B-A9F7-42FB-8A07-8631AFC923AF}&language=ES # http://actualidad.terra.es/sociedad/articulo/cuba_llama_ahorrar_energia_cambio_1957044.htm # # From Alex Krivenyshev (2007-10-25): diff --git a/make/data/tzdata/southamerica b/make/data/tzdata/southamerica index 81fdd793df4..4024e7180cd 100644 --- a/make/data/tzdata/southamerica +++ b/make/data/tzdata/southamerica @@ -231,7 +231,7 @@ Rule Arg 2008 only - Oct Sun>=15 0:00 1:00 - # Hora de verano para la República Argentina # http://buenasiembra.com.ar/esoterismo/astrologia/hora-de-verano-de-la-republica-argentina-27.html # says that standard time in Argentina from 1894-10-31 -# to 1920-05-01 was -4:16:48.25. Go with this more-precise value +# to 1920-05-01 was -4:16:48.25. Go with this more precise value # over Shanks & Pottenger. It is upward compatible with Milne, who # says Córdoba time was -4:16:48.2. diff --git a/make/data/tzdata/zone.tab b/make/data/tzdata/zone.tab index 939432d3456..3edb0d61c80 100644 --- a/make/data/tzdata/zone.tab +++ b/make/data/tzdata/zone.tab @@ -144,9 +144,8 @@ CA +744144-0944945 America/Resolute Central - NU (Resolute) CA +624900-0920459 America/Rankin_Inlet Central - NU (central) CA +5024-10439 America/Regina CST - SK (most areas) CA +5017-10750 America/Swift_Current CST - SK (midwest) -CA +5333-11328 America/Edmonton Mountain - AB; BC (E); SK (W) +CA +5333-11328 America/Edmonton Mountain - AB; BC (E); NT (E); SK (W) CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) -CA +6227-11421 America/Yellowknife Mountain - NT (central) CA +682059-1334300 America/Inuvik Mountain - NT (west) CA +4906-11631 America/Creston MST - BC (Creston) CA +5546-12014 America/Dawson_Creek MST - BC (Dawson Cr, Ft St John) @@ -162,7 +161,7 @@ CG -0416+01517 Africa/Brazzaville CH +4723+00832 Europe/Zurich CI +0519-00402 Africa/Abidjan CK -2114-15946 Pacific/Rarotonga -CL -3327-07040 America/Santiago Chile (most areas) +CL -3327-07040 America/Santiago most of Chile CL -5309-07055 America/Punta_Arenas Region of Magallanes CL -2709-10926 Pacific/Easter Easter Island CM +0403+00942 Africa/Douala @@ -174,10 +173,10 @@ CU +2308-08222 America/Havana CV +1455-02331 Atlantic/Cape_Verde CW +1211-06900 America/Curacao CX -1025+10543 Indian/Christmas -CY +3510+03322 Asia/Nicosia Cyprus (most areas) +CY +3510+03322 Asia/Nicosia most of Cyprus CY +3507+03357 Asia/Famagusta Northern Cyprus CZ +5005+01426 Europe/Prague -DE +5230+01322 Europe/Berlin Germany (most areas) +DE +5230+01322 Europe/Berlin most of Germany DE +4742+00841 Europe/Busingen Busingen DJ +1136+04309 Africa/Djibouti DK +5540+01235 Europe/Copenhagen @@ -210,7 +209,7 @@ GF +0456-05220 America/Cayenne GG +492717-0023210 Europe/Guernsey GH +0533-00013 Africa/Accra GI +3608-00521 Europe/Gibraltar -GL +6411-05144 America/Nuuk Greenland (most areas) +GL +6411-05144 America/Nuuk most of Greenland GL +7646-01840 America/Danmarkshavn National Park (east coast) GL +7029-02158 America/Scoresbysund Scoresbysund/Ittoqqortoormiit GL +7634-06847 America/Thule Thule/Pituffik @@ -258,7 +257,7 @@ KP +3901+12545 Asia/Pyongyang KR +3733+12658 Asia/Seoul KW +2920+04759 Asia/Kuwait KY +1918-08123 America/Cayman -KZ +4315+07657 Asia/Almaty Kazakhstan (most areas) +KZ +4315+07657 Asia/Almaty most of Kazakhstan KZ +4448+06528 Asia/Qyzylorda Qyzylorda/Kyzylorda/Kzyl-Orda KZ +5312+06337 Asia/Qostanay Qostanay/Kostanay/Kustanay KZ +5017+05710 Asia/Aqtobe Aqtobe/Aktobe @@ -282,12 +281,12 @@ MD +4700+02850 Europe/Chisinau ME +4226+01916 Europe/Podgorica MF +1804-06305 America/Marigot MG -1855+04731 Indian/Antananarivo -MH +0709+17112 Pacific/Majuro Marshall Islands (most areas) +MH +0709+17112 Pacific/Majuro most of Marshall Islands MH +0905+16720 Pacific/Kwajalein Kwajalein MK +4159+02126 Europe/Skopje ML +1239-00800 Africa/Bamako MM +1647+09610 Asia/Yangon -MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas) +MN +4755+10653 Asia/Ulaanbaatar most of Mongolia MN +4801+09139 Asia/Hovd Bayan-Olgiy, Govi-Altai, Hovd, Uvs, Zavkhan MN +4804+11430 Asia/Choibalsan Dornod, Sukhbaatar MO +221150+1133230 Asia/Macau @@ -325,7 +324,7 @@ NO +5955+01045 Europe/Oslo NP +2743+08519 Asia/Kathmandu NR -0031+16655 Pacific/Nauru NU -1901-16955 Pacific/Niue -NZ -3652+17446 Pacific/Auckland New Zealand (most areas) +NZ -3652+17446 Pacific/Auckland most of New Zealand NZ -4357-17633 Pacific/Chatham Chatham Islands OM +2336+05835 Asia/Muscat PA +0858-07932 America/Panama @@ -333,7 +332,7 @@ PE -1203-07703 America/Lima PF -1732-14934 Pacific/Tahiti Society Islands PF -0900-13930 Pacific/Marquesas Marquesas Islands PF -2308-13457 Pacific/Gambier Gambier Islands -PG -0930+14710 Pacific/Port_Moresby Papua New Guinea (most areas) +PG -0930+14710 Pacific/Port_Moresby most of Papua New Guinea PG -0613+15534 Pacific/Bougainville Bougainville PH +1435+12100 Asia/Manila PK +2452+06703 Asia/Karachi @@ -379,7 +378,7 @@ RU +4310+13156 Asia/Vladivostok MSK+07 - Amur River RU +643337+1431336 Asia/Ust-Nera MSK+07 - Oymyakonsky RU +5934+15048 Asia/Magadan MSK+08 - Magadan RU +4658+14242 Asia/Sakhalin MSK+08 - Sakhalin Island -RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); North Kuril Is +RU +6728+15343 Asia/Srednekolymsk MSK+08 - Sakha (E); N Kuril Is RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea RW -0157+03004 Africa/Kigali @@ -420,7 +419,7 @@ TT +1039-06131 America/Port_of_Spain TV -0831+17913 Pacific/Funafuti TW +2503+12130 Asia/Taipei TZ -0648+03917 Africa/Dar_es_Salaam -UA +5026+03031 Europe/Kyiv Ukraine (most areas) +UA +5026+03031 Europe/Kyiv most of Ukraine UG +0019+03225 Africa/Kampala UM +2813-17722 Pacific/Midway Midway Islands UM +1917+16637 Pacific/Wake Wake Island @@ -443,7 +442,7 @@ US +465042-1012439 America/North_Dakota/New_Salem Central - ND (Morton rural) US +471551-1014640 America/North_Dakota/Beulah Central - ND (Mercer) US +394421-1045903 America/Denver Mountain (most areas) US +433649-1161209 America/Boise Mountain - ID (south); OR (east) -US +332654-1120424 America/Phoenix MST - Arizona (except Navajo) +US +332654-1120424 America/Phoenix MST - AZ (except Navajo) US +340308-1181434 America/Los_Angeles Pacific US +611305-1495401 America/Anchorage Alaska (most areas) US +581807-1342511 America/Juneau Alaska - Juneau area @@ -451,7 +450,7 @@ US +571035-1351807 America/Sitka Alaska - Sitka area US +550737-1313435 America/Metlakatla Alaska - Annette Island US +593249-1394338 America/Yakutat Alaska - Yakutat US +643004-1652423 America/Nome Alaska (west) -US +515248-1763929 America/Adak Aleutian Islands +US +515248-1763929 America/Adak Alaska - western Aleutians US +211825-1575130 Pacific/Honolulu Hawaii UY -345433-0561245 America/Montevideo UZ +3940+06648 Asia/Samarkand Uzbekistan (west) diff --git a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java index ef278203182..3762eb820bb 100644 --- a/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java +++ b/src/java.base/share/classes/sun/util/calendar/ZoneInfoFile.java @@ -608,6 +608,17 @@ private static ZoneInfo getZoneInfo(String zoneId, params[8] = endRule.secondOfDay * 1000; params[9] = toSTZTime[endRule.timeDefinition]; dstSavings = (startRule.offsetAfter - startRule.offsetBefore) * 1000; + + // Note: known mismatching -> Africa/Cairo + // ZoneInfo : startDayOfWeek=5 <= Thursday + // startTime=86400000 <= 24:00 + // This: startDayOfWeek=6 <= Friday + // startTime=0 <= 0:00 + if (zoneId.equals("Africa/Cairo") && + params[7] == Calendar.FRIDAY && params[8] == 0) { + params[7] = Calendar.THURSDAY; + params[8] = SECONDS_PER_DAY * 1000; + } } else if (nTrans > 0) { // only do this if there is something in table already if (lastyear < LASTYEAR) { // ZoneInfo has an ending entry for 2037 diff --git a/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java b/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java index bf7918659ae..2763ac30ca7 100644 --- a/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java +++ b/src/java.base/share/classes/sun/util/resources/TimeZoneNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -845,9 +845,7 @@ protected final Object[][] getContents() { {"Europe/Jersey", GMTBST}, {"Europe/Kaliningrad", EET}, {"Europe/Kiev", EET}, - {"Europe/Kirov", new String[] {"Kirov Standard Time", "GMT+03:00", - "Kirov Daylight Time", "GMT+03:00", - "Kirov Time", "GMT+03:00"}}, + {"Europe/Kirov", MSK}, {"Europe/Lisbon", WET}, {"Europe/Ljubljana", CET}, {"Europe/London", GMTBST}, diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION index 0f66ee12c94..c5483b48512 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/VERSION +++ b/test/jdk/java/util/TimeZone/TimeZoneData/VERSION @@ -1 +1 @@ -tzdata2022g +tzdata2023c diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt index d495743b268..07c5edbafee 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt +++ b/test/jdk/java/util/TimeZone/TimeZoneData/aliases.txt @@ -211,6 +211,7 @@ Link America/Argentina/Cordoba America/Rosario Link America/Tijuana America/Santa_Isabel Link America/Denver America/Shiprock Link America/Toronto America/Thunder_Bay +Link America/Edmonton America/Yellowknife Link Pacific/Auckland Antarctica/South_Pole Link Asia/Shanghai Asia/Chongqing Link Asia/Shanghai Asia/Harbin diff --git a/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt b/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt index 44db4dbdb81..03f5305e65e 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt +++ b/test/jdk/java/util/TimeZone/TimeZoneData/displaynames.txt @@ -92,7 +92,6 @@ America/Vancouver PST PDT America/Whitehorse MST America/Winnipeg CST CDT America/Yakutat AKST AKDT -America/Yellowknife MST MDT Antarctica/Macquarie AEST AEDT Asia/Beirut EET EEST Asia/Famagusta EET EEST @@ -144,6 +143,7 @@ Europe/Dublin IST/GMT IST/GMT Europe/Gibraltar CET CEST Europe/Helsinki EET EEST Europe/Kaliningrad EET +Europe/Kirov MSK Europe/Kyiv EET EEST Europe/Lisbon WET WEST Europe/London GMT/BST GMT/BST @@ -160,6 +160,7 @@ Europe/Tallinn EET EEST Europe/Tirane CET CEST Europe/Vienna CET CEST Europe/Vilnius EET EEST +Europe/Volgograd MSK Europe/Warsaw CET CEST Europe/Zurich CET CEST HST HST diff --git a/test/jdk/java/util/TimeZone/TimeZoneTest.java b/test/jdk/java/util/TimeZone/TimeZoneTest.java index d31d1722b7b..8e5d403f87b 100644 --- a/test/jdk/java/util/TimeZone/TimeZoneTest.java +++ b/test/jdk/java/util/TimeZone/TimeZoneTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -25,7 +25,7 @@ * @test * @bug 4028006 4044013 4096694 4107276 4107570 4112869 4130885 7039469 7126465 7158483 * 8008577 8077685 8098547 8133321 8138716 8148446 8151876 8159684 8166875 8181157 - * 8228469 8274407 + * 8228469 8274407 8305113 * @modules java.base/sun.util.resources * @library /java/text/testlib * @summary test TimeZone @@ -121,7 +121,7 @@ public void TestShortZoneIDs() throws Exception { new ZoneDescriptor("GMT", 0, false), new ZoneDescriptor("UTC", 0, false), new ZoneDescriptor("ECT", 60, true), - new ZoneDescriptor("ART", 120, false), + new ZoneDescriptor("ART", 120, true), new ZoneDescriptor("EET", 120, true), new ZoneDescriptor("EAT", 180, false), new ZoneDescriptor("MET", 60, true), From 2bf98280c6fa939dff38761291b614295295bfcb Mon Sep 17 00:00:00 2001 From: Jaroslav Bachorik Date: Mon, 17 Apr 2023 13:41:54 +0000 Subject: [PATCH 041/217] 8245877: assert(_value != __null) failed: resolving NULL _value in JvmtiExport::post_compiled_method_load Backport-of: b969136b9fcf5f977ebe466f5f9de5c520413e84 --- src/hotspot/share/code/nmethod.cpp | 2 ++ src/hotspot/share/prims/jvmtiExport.cpp | 1 + src/hotspot/share/prims/jvmtiImpl.cpp | 6 +++--- test/hotspot/jtreg/ProblemList.txt | 1 - 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 7fe1d05ff1c..939b3a2f378 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -1657,6 +1657,8 @@ void nmethod::post_compiled_method_load_event(JvmtiThreadState* state) { if (is_not_entrant() && can_convert_to_zombie()) { return; } + // Ensure the sweeper can't collect this nmethod until it become "active" with JvmtiThreadState::nmethods_do. + mark_as_seen_on_stack(); } // This is a bad time for a safepoint. We don't want diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index 0c8a43680fa..fe9631c08ac 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -2216,6 +2216,7 @@ void JvmtiExport::post_compiled_method_load(JvmtiEnv* env, nmethod *nm) { ResourceMark rm(thread); HandleMark hm(thread); + assert(!nm->is_zombie(), "nmethod zombie in post_compiled_method_load"); // Add inlining information jvmtiCompiledMethodLoadInlineRecord* inlinerecord = create_inline_record(nm); // Pass inlining information through the void pointer diff --git a/src/hotspot/share/prims/jvmtiImpl.cpp b/src/hotspot/share/prims/jvmtiImpl.cpp index ba79e19392c..c542f110122 100644 --- a/src/hotspot/share/prims/jvmtiImpl.cpp +++ b/src/hotspot/share/prims/jvmtiImpl.cpp @@ -960,10 +960,10 @@ JvmtiDeferredEvent JvmtiDeferredEventQueue::dequeue() { } void JvmtiDeferredEventQueue::post(JvmtiEnv* env) { - // Post and destroy queue nodes + // Post events while nmethods are still in the queue and can't be unloaded or made zombie while (_queue_head != NULL) { - JvmtiDeferredEvent event = dequeue(); - event.post_compiled_method_load_event(env); + _queue_head->event().post_compiled_method_load_event(env); + dequeue(); } } diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 8d5ea5105a8..3f8db254ae4 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -113,7 +113,6 @@ serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatIntervalTest.java 8214 serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorStatArrayCorrectnessTest.java 8224150 generic-all serviceability/jvmti/ModuleAwareAgents/ThreadStart/MAAThreadStart.java 8225354 windows-all serviceability/dcmd/gc/RunFinalizationTest.java 8227120 linux-all,windows-x64 -serviceability/jvmti/CompiledMethodLoad/Zombie.java 8245877 linux-aarch64 serviceability/sa/ClhsdbCDSCore.java 8294316,8269982,8267433 macosx-aarch64,macosx-x64 serviceability/sa/ClhsdbFindPC.java#id1 8294316,8269982,8267433 macosx-aarch64,macosx-x64 From fc037105b479886a4abdf90f30d328d5db28cc39 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 18 Apr 2023 09:19:33 +0000 Subject: [PATCH 042/217] 8287246: DSAKeyValue should check for missing params instead of relying on KeyFactory provider Backport-of: f235955eefb1141a2e72116dfcf345e40416f059 --- .../xml/dsig/internal/dom/DOMKeyValue.java | 48 +++++++------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java index 48552f3947a..307d0ae45ce 100644 --- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java +++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMKeyValue.java @@ -21,7 +21,7 @@ * under the License. */ /* - * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. */ package org.jcp.xml.dsig.internal.dom; @@ -300,35 +300,23 @@ DSAPublicKey unmarshalKeyValue(Element kvtElem) ("unable to create DSA KeyFactory: " + e.getMessage()); } } - Element curElem = DOMUtils.getFirstChildElement(kvtElem); - if (curElem == null) { - throw new MarshalException("KeyValue must contain at least one type"); - } - // check for P and Q - BigInteger p = null; - BigInteger q = null; - if ("P".equals(curElem.getLocalName()) && XMLSignature.XMLNS.equals(curElem.getNamespaceURI())) { - p = decode(curElem); - curElem = DOMUtils.getNextSiblingElement(curElem, "Q", XMLSignature.XMLNS); - q = decode(curElem); - curElem = DOMUtils.getNextSiblingElement(curElem); - } - BigInteger g = null; - if (curElem != null - && "G".equals(curElem.getLocalName()) && XMLSignature.XMLNS.equals(curElem.getNamespaceURI())) { - g = decode(curElem); - curElem = DOMUtils.getNextSiblingElement(curElem, "Y", XMLSignature.XMLNS); - } - BigInteger y = null; - if (curElem != null) { - y = decode(curElem); - curElem = DOMUtils.getNextSiblingElement(curElem); - } - //if (curElem != null && "J".equals(curElem.getLocalName())) { - //j = new DOMCryptoBinary(curElem.getFirstChild()); - // curElem = DOMUtils.getNextSiblingElement(curElem); - //} - //@@@ do we care about j, pgenCounter or seed? + // P, Q, and G are optional according to the XML Signature + // Recommendation as they might be known from application context, + // but this implementation does not provide a mechanism or API for + // an application to supply the missing parameters, so they are + // required to be specified. + Element curElem = + DOMUtils.getFirstChildElement(kvtElem, "P", XMLSignature.XMLNS); + BigInteger p = decode(curElem); + curElem = + DOMUtils.getNextSiblingElement(curElem, "Q", XMLSignature.XMLNS); + BigInteger q = decode(curElem); + curElem = + DOMUtils.getNextSiblingElement(curElem, "G", XMLSignature.XMLNS); + BigInteger g = decode(curElem); + curElem = + DOMUtils.getNextSiblingElement(curElem, "Y", XMLSignature.XMLNS); + BigInteger y = decode(curElem); DSAPublicKeySpec spec = new DSAPublicKeySpec(y, p, q, g); return (DSAPublicKey) generatePublicKey(dsakf, spec); } From 3aa85f9e256051fbc1207c296f0d6d1d2917769d Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 18 Apr 2023 12:51:32 +0000 Subject: [PATCH 043/217] 8287007: [cgroups] Consistently use stringStream throughout parsing code Backport-of: e0baf012b111e422ddf39a577b1b4af2599fd00d --- .../os/linux/cgroupV1Subsystem_linux.cpp | 34 +++----- .../os/linux/cgroupV2Subsystem_linux.cpp | 15 ++-- .../gtest/runtime/test_os_linux_cgroups.cpp | 86 +++++++++++++++++++ .../CgroupV1SubsystemControllerTest.java | 78 +++++++++++++++++ .../CgroupV2SubsystemControllerTest.java | 64 ++++++++++++++ 5 files changed, 243 insertions(+), 34 deletions(-) create mode 100644 test/hotspot/gtest/runtime/test_os_linux_cgroups.cpp create mode 100644 test/jdk/jdk/internal/platform/cgroup/CgroupV1SubsystemControllerTest.java create mode 100644 test/jdk/jdk/internal/platform/cgroup/CgroupV2SubsystemControllerTest.java diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp index 79dd256ac61..e62dcf4f759 100644 --- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp @@ -38,40 +38,26 @@ * on the contents of the mountinfo and cgroup files. */ void CgroupV1Controller::set_subsystem_path(char *cgroup_path) { - char buf[MAXPATHLEN+1]; + stringStream ss; if (_root != NULL && cgroup_path != NULL) { if (strcmp(_root, "/") == 0) { - int buflen; - strncpy(buf, _mount_point, MAXPATHLEN); - buf[MAXPATHLEN-1] = '\0'; + ss.print_raw(_mount_point); if (strcmp(cgroup_path,"/") != 0) { - buflen = strlen(buf); - if ((buflen + strlen(cgroup_path)) > (MAXPATHLEN-1)) { - return; - } - strncat(buf, cgroup_path, MAXPATHLEN-buflen); - buf[MAXPATHLEN-1] = '\0'; + ss.print_raw(cgroup_path); } - _path = os::strdup(buf); + _path = os::strdup(ss.base()); } else { if (strcmp(_root, cgroup_path) == 0) { - strncpy(buf, _mount_point, MAXPATHLEN); - buf[MAXPATHLEN-1] = '\0'; - _path = os::strdup(buf); + ss.print_raw(_mount_point); + _path = os::strdup(ss.base()); } else { char *p = strstr(cgroup_path, _root); if (p != NULL && p == _root) { if (strlen(cgroup_path) > strlen(_root)) { - int buflen; - strncpy(buf, _mount_point, MAXPATHLEN); - buf[MAXPATHLEN-1] = '\0'; - buflen = strlen(buf); - if ((buflen + strlen(cgroup_path) - strlen(_root)) > (MAXPATHLEN-1)) { - return; - } - strncat(buf, cgroup_path + strlen(_root), MAXPATHLEN-buflen); - buf[MAXPATHLEN-1] = '\0'; - _path = os::strdup(buf); + ss.print_raw(_mount_point); + const char* cg_path_sub = cgroup_path + strlen(_root); + ss.print_raw(cg_path_sub); + _path = os::strdup(ss.base()); } } } diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp index b1035f89bf0..2456385af7a 100644 --- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp @@ -234,17 +234,12 @@ void CgroupV2Subsystem::print_version_specific_info(outputStream* st) { } char* CgroupV2Controller::construct_path(char* mount_path, char *cgroup_path) { - char buf[MAXPATHLEN+1]; - int buflen; - strncpy(buf, mount_path, MAXPATHLEN); - buf[MAXPATHLEN] = '\0'; - buflen = strlen(buf); - if ((buflen + strlen(cgroup_path)) > MAXPATHLEN) { - return NULL; + stringStream ss; + ss.print_raw(mount_path); + if (strcmp(cgroup_path, "/") != 0) { + ss.print_raw(cgroup_path); } - strncat(buf, cgroup_path, MAXPATHLEN-buflen); - buf[MAXPATHLEN] = '\0'; - return os::strdup(buf); + return os::strdup(ss.base()); } char* CgroupV2Subsystem::pids_max_val() { diff --git a/test/hotspot/gtest/runtime/test_os_linux_cgroups.cpp b/test/hotspot/gtest/runtime/test_os_linux_cgroups.cpp new file mode 100644 index 00000000000..9130c0c701d --- /dev/null +++ b/test/hotspot/gtest/runtime/test_os_linux_cgroups.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. + * 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. + */ + +#include "precompiled.hpp" + +#ifdef LINUX + +#include "cgroupV1Subsystem_linux.hpp" +#include "cgroupV2Subsystem_linux.hpp" +#include "unittest.hpp" + +typedef struct { + const char* mount_path; + const char* root_path; + const char* cgroup_path; + const char* expected_path; +} TestCase; + +TEST(os_linux_cgroup, set_cgroupv1_subsystem_path) { + TestCase host = { + "/sys/fs/cgroup/memory", // mount_path + "/", // root_path + "/user.slice/user-1000.slice/user@1000.service", // cgroup_path + "/sys/fs/cgroup/memory/user.slice/user-1000.slice/user@1000.service" // expected_path + }; + TestCase container_engine = { + "/sys/fs/cgroup/mem", // mount_path + "/user.slice/user-1000.slice/user@1000.service", // root_path + "/user.slice/user-1000.slice/user@1000.service", // cgroup_path + "/sys/fs/cgroup/mem" // expected_path + }; + int length = 2; + TestCase* testCases[] = { &host, + &container_engine }; + for (int i = 0; i < length; i++) { + CgroupV1Controller* ctrl = new CgroupV1Controller( (char*)testCases[i]->root_path, + (char*)testCases[i]->mount_path); + ctrl->set_subsystem_path((char*)testCases[i]->cgroup_path); + ASSERT_STREQ(testCases[i]->expected_path, ctrl->subsystem_path()); + } +} + +TEST(os_linux_cgroup, set_cgroupv2_subsystem_path) { + TestCase at_mount_root = { + "/sys/fs/cgroup", // mount_path + NULL, // root_path, ignored + "/", // cgroup_path + "/sys/fs/cgroup" // expected_path + }; + TestCase sub_path = { + "/sys/fs/cgroup", // mount_path + NULL, // root_path, ignored + "/foobar", // cgroup_path + "/sys/fs/cgroup/foobar" // expected_path + }; + int length = 2; + TestCase* testCases[] = { &at_mount_root, + &sub_path }; + for (int i = 0; i < length; i++) { + CgroupV2Controller* ctrl = new CgroupV2Controller( (char*)testCases[i]->mount_path, + (char*)testCases[i]->cgroup_path); + ASSERT_STREQ(testCases[i]->expected_path, ctrl->subsystem_path()); + } +} + +#endif diff --git a/test/jdk/jdk/internal/platform/cgroup/CgroupV1SubsystemControllerTest.java b/test/jdk/jdk/internal/platform/cgroup/CgroupV1SubsystemControllerTest.java new file mode 100644 index 00000000000..a97edd581fe --- /dev/null +++ b/test/jdk/jdk/internal/platform/cgroup/CgroupV1SubsystemControllerTest.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. + * 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. + */ + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import jdk.internal.platform.cgroupv1.CgroupV1SubsystemController; + +/* + * @test + * @key cgroups + * @requires os.family == "linux" + * @modules java.base/jdk.internal.platform.cgroupv1 + * @library /test/lib + * @run junit/othervm CgroupV1SubsystemControllerTest + */ +public class CgroupV1SubsystemControllerTest { + + + /* + * Common case: Containers + */ + @Test + public void testCgPathEqualsRoot() { + String root = "/machine.slice/libpod-7145e2e7dbeab5aa96bd79beed79eda286a2d299a0ee386e704cad9f53a70979.scope"; + String mountPoint = "/somemount"; + CgroupV1SubsystemController ctrl = new CgroupV1SubsystemController(root, mountPoint); + ctrl.setPath("/machine.slice/libpod-7145e2e7dbeab5aa96bd79beed79eda286a2d299a0ee386e704cad9f53a70979.scope"); + assertEquals(mountPoint, ctrl.path()); + } + + /* + * Common case: Host + */ + @Test + public void testCgPathNonEmptyRoot() { + String root = "/"; + String mountPoint = "/sys/fs/cgroup/memory"; + CgroupV1SubsystemController ctrl = new CgroupV1SubsystemController(root, mountPoint); + String cgroupPath = "/subpath"; + ctrl.setPath(cgroupPath); + String expectedPath = mountPoint + cgroupPath; + assertEquals(expectedPath, ctrl.path()); + } + + @Test + public void testCgPathSubstring() { + String root = "/foo/bar/baz"; + String mountPoint = "/sys/fs/cgroup/memory"; + CgroupV1SubsystemController ctrl = new CgroupV1SubsystemController(root, mountPoint); + String cgroupPath = "/foo/bar/baz/some"; + ctrl.setPath(cgroupPath); + String expectedPath = mountPoint + "/some"; + assertEquals(expectedPath, ctrl.path()); + } + +} diff --git a/test/jdk/jdk/internal/platform/cgroup/CgroupV2SubsystemControllerTest.java b/test/jdk/jdk/internal/platform/cgroup/CgroupV2SubsystemControllerTest.java new file mode 100644 index 00000000000..a2df5f982d8 --- /dev/null +++ b/test/jdk/jdk/internal/platform/cgroup/CgroupV2SubsystemControllerTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022, Red Hat, Inc. + * 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. + */ + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +import jdk.internal.platform.cgroupv2.CgroupV2SubsystemController; + +/* + * @test + * @key cgroups + * @requires os.family == "linux" + * @modules java.base/jdk.internal.platform.cgroupv2 + * @library /test/lib + * @run junit/othervm CgroupV2SubsystemControllerTest + */ +public class CgroupV2SubsystemControllerTest { + + + /* + * Common case: No nested cgroup path (i.e. at the unified root) + */ + @Test + public void testCgPathAtRoot() { + String mountPoint = "/sys/fs/cgroup"; + String cgroupPath = "/"; + CgroupV2SubsystemController ctrl = new CgroupV2SubsystemController(mountPoint, cgroupPath); + assertEquals(mountPoint, ctrl.path()); + } + + /* + * Cgroup path at a sub-path + */ + @Test + public void testCgPathNonEmptyRoot() { + String mountPoint = "/sys/fs/cgroup"; + String cgroupPath = "/foobar"; + CgroupV2SubsystemController ctrl = new CgroupV2SubsystemController(mountPoint, cgroupPath); + String expectedPath = mountPoint + cgroupPath; + assertEquals(expectedPath, ctrl.path()); + } + +} From b0e142e763959a6d9d156e51faef1d882c2d24f5 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 18 Apr 2023 12:53:07 +0000 Subject: [PATCH 044/217] 8292755: Non-default method in interface leads to a stack overflow in JShell Backport-of: 2a3879180e63aa0a7a19479f061fe78d7885da7b --- .../com/sun/tools/javac/comp/Attr.java | 17 +- test/langtools/jdk/jshell/ClassesTest.java | 16 +- .../tools/javac/recovery/MethodModifiers.java | 162 ++++++++++++++++++ 3 files changed, 186 insertions(+), 9 deletions(-) create mode 100644 test/langtools/tools/javac/recovery/MethodModifiers.java diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 47c8217a255..59eb9264249 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -1183,15 +1183,16 @@ public void visitMethodDef(JCMethodDecl tree) { } if (isDefaultMethod || (tree.sym.flags() & (ABSTRACT | NATIVE)) == 0) log.error(tree.pos(), Errors.MissingMethBodyOrDeclAbstract); - } else if ((tree.sym.flags() & (ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) { - if ((owner.flags() & INTERFACE) != 0) { - log.error(tree.body.pos(), Errors.IntfMethCantHaveBody); - } else { - log.error(tree.pos(), Errors.AbstractMethCantHaveBody); - } - } else if ((tree.mods.flags & NATIVE) != 0) { - log.error(tree.pos(), Errors.NativeMethCantHaveBody); } else { + if ((tree.sym.flags() & (ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) { + if ((owner.flags() & INTERFACE) != 0) { + log.error(tree.body.pos(), Errors.IntfMethCantHaveBody); + } else { + log.error(tree.pos(), Errors.AbstractMethCantHaveBody); + } + } else if ((tree.mods.flags & NATIVE) != 0) { + log.error(tree.pos(), Errors.NativeMethCantHaveBody); + } // Add an implicit super() call unless an explicit call to // super(...) or this(...) is given // or we are compiling class java.lang.Object. diff --git a/test/langtools/jdk/jshell/ClassesTest.java b/test/langtools/jdk/jshell/ClassesTest.java index 082d757b02f..efeff5ef139 100644 --- a/test/langtools/jdk/jshell/ClassesTest.java +++ b/test/langtools/jdk/jshell/ClassesTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8145239 8129559 8080354 8189248 8010319 8246353 8247456 + * @bug 8145239 8129559 8080354 8189248 8010319 8246353 8247456 8292755 * @summary Tests for EvaluationState.classes * @build KullaTesting TestingInputStream ExpectedDiagnostic * @run testng ClassesTest @@ -342,4 +342,18 @@ public void testCircular() { assertEval("new A()"); } + public void testDefaultMethodInInterface() { + assertEvalFail(""" + interface C { + public void run() { + try { + throw IllegalStateException(); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + } + """); + } + } diff --git a/test/langtools/tools/javac/recovery/MethodModifiers.java b/test/langtools/tools/javac/recovery/MethodModifiers.java new file mode 100644 index 00000000000..3212d20f47c --- /dev/null +++ b/test/langtools/tools/javac/recovery/MethodModifiers.java @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2022, 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. + */ + +/* + * @test + * @bug 8292755 + * @summary Verify error recovery related to method modifiers. + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.classfile + * @build toolbox.ToolBox toolbox.JavacTask + * @run main MethodModifiers + */ + +import java.nio.file.Path; +import java.util.List; +import java.util.Objects; + +import toolbox.JavacTask; +import toolbox.Task.Expect; +import toolbox.Task.OutputKind; +import toolbox.TestRunner; +import toolbox.ToolBox; + +public class MethodModifiers extends TestRunner { + + ToolBox tb; + + public MethodModifiers() { + super(System.err); + tb = new ToolBox(); + } + + public static void main(String[] args) throws Exception { + MethodModifiers t = new MethodModifiers(); + t.runTests(); + } + + @Test + public void testNonDefaultMethodInterface() throws Exception { + String code = """ + interface Test { + void test() { + try { + unresolvable(); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", + "-XDshould-stop.at=FLOW", + "-XDdev") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "Test.java:2:17: compiler.err.intf.meth.cant.have.body", + "Test.java:4:13: compiler.err.cant.resolve.location.args: kindname.method, unresolvable, , , (compiler.misc.location: kindname.interface, Test, null)", + "2 errors" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + + @Test + public void testAbstractMethodWithBody() throws Exception { + String code = """ + abstract class Test { + abstract void test() { + try { + unresolvable(); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", + "-XDshould-stop.at=FLOW", + "-XDdev") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "Test.java:2:19: compiler.err.abstract.meth.cant.have.body", + "Test.java:4:13: compiler.err.cant.resolve.location.args: kindname.method, unresolvable, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + + @Test + public void testNativeMethodWithBody() throws Exception { + String code = """ + class Test { + native void test() { + try { + unresolvable(); + } catch (Throwable t) { + throw new RuntimeException(t); + } + } + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics", + "-XDshould-stop.at=FLOW", + "-XDdev") + .sources(code) + .outdir(curPath) + .run(Expect.FAIL) + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "Test.java:2:17: compiler.err.native.meth.cant.have.body", + "Test.java:4:13: compiler.err.cant.resolve.location.args: kindname.method, unresolvable, , , (compiler.misc.location: kindname.class, Test, null)", + "2 errors" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + +} From e91b87e27e9d34b6592d798e7ccf704096e36074 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 18 Apr 2023 12:55:25 +0000 Subject: [PATCH 045/217] 8294906: Memory leak in PKCS11 NSS TLS server Backport-of: 94caecbe574227b232e22d9f56361f8ecd507be6 --- .../pkcs11/P11TlsKeyMaterialGenerator.java | 14 +++++--- .../crypto/provider/TLS/TestKeyMaterial.java | 31 +++++++++++++++-- .../sun/crypto/provider/TLS/keymatdata.txt | 34 +++++++++++++++++++ .../security/pkcs11/tls/TestKeyMaterial.java | 14 +++++--- .../sun/security/pkcs11/tls/keymatdata.txt | 34 +++++++++++++++++++ 5 files changed, 116 insertions(+), 11 deletions(-) diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java index c8d11663311..269bf489359 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11TlsKeyMaterialGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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 @@ -209,15 +209,19 @@ protected SecretKey engineGenerateKey() { SecretKey clientMacKey, serverMacKey; // The MAC size may be zero for GCM mode. - // - // PKCS11 does not support GCM mode as the author made the comment, - // so the macBits is unlikely to be zero. It's only a place holder. if (macBits != 0) { clientMacKey = P11Key.secretKey (session, out.hClientMacSecret, "MAC", macBits, attributes); serverMacKey = P11Key.secretKey (session, out.hServerMacSecret, "MAC", macBits, attributes); } else { + // NSS allocates MAC keys even if macBits is zero + if (out.hClientMacSecret != CK_INVALID_HANDLE) { + token.p11.C_DestroyObject(session.id(), out.hClientMacSecret); + } + if (out.hServerMacSecret != CK_INVALID_HANDLE) { + token.p11.C_DestroyObject(session.id(), out.hServerMacSecret); + } clientMacKey = null; serverMacKey = null; } @@ -229,6 +233,8 @@ protected SecretKey engineGenerateKey() { serverCipherKey = P11Key.secretKey(session, out.hServerKey, cipherAlgorithm, expandedKeyBits, attributes); } else { + assert out.hClientKey == 0; + assert out.hServerKey == 0; clientCipherKey = null; serverCipherKey = null; } diff --git a/test/jdk/com/sun/crypto/provider/TLS/TestKeyMaterial.java b/test/jdk/com/sun/crypto/provider/TLS/TestKeyMaterial.java index d07c9ee3e52..983e8acb4c3 100644 --- a/test/jdk/com/sun/crypto/provider/TLS/TestKeyMaterial.java +++ b/test/jdk/com/sun/crypto/provider/TLS/TestKeyMaterial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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 @@ -61,6 +61,7 @@ public static void main(String[] args) throws Exception { byte[] clientRandom = null; byte[] serverRandom = null; String cipherAlgorithm = null; + String hashAlgorithm = null; // TLS1.2+ only int keyLength = 0; int expandedKeyLength = 0; int ivLength = 0; @@ -94,6 +95,8 @@ public static void main(String[] args) throws Exception { serverRandom = parse(data); } else if (line.startsWith("km-cipalg:")) { cipherAlgorithm = data; + } else if (line.startsWith("km-hashalg:")) { + hashAlgorithm = data; } else if (line.startsWith("km-keylen:")) { keyLength = Integer.parseInt(data); } else if (line.startsWith("km-explen:")) { @@ -119,14 +122,36 @@ public static void main(String[] args) throws Exception { n++; KeyGenerator kg = - KeyGenerator.getInstance("SunTlsKeyMaterial", provider); + KeyGenerator.getInstance(minor == 3 ? + "SunTls12KeyMaterial" : + "SunTlsKeyMaterial", provider); SecretKey masterKey = new SecretKeySpec(master, "TlsMasterSecret"); + int prfHashLength, prfBlockSize; + + if (hashAlgorithm != null) { + switch (hashAlgorithm) { + case "SHA-256": + prfHashLength = 32; + prfBlockSize = 64; + break; + case "SHA-384": + prfHashLength = 48; + prfBlockSize = 128; + break; + default: + throw new RuntimeException("Unexpected hashalg: " + + hashAlgorithm); + } + } else { + prfHashLength = -1; + prfBlockSize = -1; + } TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec(masterKey, major, minor, clientRandom, serverRandom, cipherAlgorithm, keyLength, expandedKeyLength, ivLength, macLength, - null, -1, -1); + hashAlgorithm, prfHashLength, prfBlockSize); kg.init(spec); TlsKeyMaterialSpec result = diff --git a/test/jdk/com/sun/crypto/provider/TLS/keymatdata.txt b/test/jdk/com/sun/crypto/provider/TLS/keymatdata.txt index 391f300007d..1d1ee636914 100644 --- a/test/jdk/com/sun/crypto/provider/TLS/keymatdata.txt +++ b/test/jdk/com/sun/crypto/provider/TLS/keymatdata.txt @@ -3646,3 +3646,37 @@ km-civ: 17:bd:47:89:54:be:04:23 km-siv: 34:8a:e8:24:84:38:c4:e1 km-cmackey: e8:f0:b5:7b:a7:cc:2f:5e:43:ef:d3:dd:4e:8c:f9:6f:51:d7:84:df km-smackey: fc:0c:77:20:c2:28:d3:11:ba:57:13:d8:0b:2d:f1:30:89:c6:35:69 +km-master: f1:05:15:45:33:be:50:d6:88:0b:03:bb:88:9b:ef:d4:3b:98:aa:40:13:71:3c:1c:d9:df:34:c7:50:75:ad:5c:0a:d4:fe:ed:d5:58:6b:ff:2b:ce:c6:12:bc:6b:7e:dc +km-major: 3 +km-minor: 3 +km-crandom: 42:f3:36:8e:9d:c9:69:3e:c1:8a:38:d3:e0:ec:2b:58:c2:e0:0c:de:4f:f3:af:51:d2:5c:bc:b2:c3:3b:1e:56 +km-srandom: 42:f3:36:8e:fa:fd:23:3e:fd:f9:bc:88:3c:98:93:f3:c3:1d:9c:2a:4a:3b:02:a7:40:d4:64:04:59:e9:65:97 +km-cipalg: AES +km-hashalg: SHA-256 +km-keylen: 16 +km-explen: 0 +km-ivlen: 4 +km-maclen: 0 +km-ccipkey: 60:7a:45:a9:6e:76:58:ea:d9:44:c5:25:f8:92:f1:26 +km-scipkey: 42:c0:ed:75:a2:51:21:7c:50:74:9d:78:9a:f7:35:2b +km-civ: a1:3c:3e:4a +km-siv: 85:ab:ee:70 +km-cmackey: (null) +km-smackey: (null) +km-master: f1:05:15:45:33:be:50:d6:88:0b:03:bb:88:9b:ef:d4:3b:98:aa:40:13:71:3c:1c:d9:df:34:c7:50:75:ad:5c:0a:d4:fe:ed:d5:58:6b:ff:2b:ce:c6:12:bc:6b:7e:dc +km-major: 3 +km-minor: 3 +km-crandom: 42:f3:36:8e:9d:c9:69:3e:c1:8a:38:d3:e0:ec:2b:58:c2:e0:0c:de:4f:f3:af:51:d2:5c:bc:b2:c3:3b:1e:56 +km-srandom: 42:f3:36:8e:fa:fd:23:3e:fd:f9:bc:88:3c:98:93:f3:c3:1d:9c:2a:4a:3b:02:a7:40:d4:64:04:59:e9:65:97 +km-cipalg: AES +km-hashalg: SHA-384 +km-keylen: 32 +km-explen: 0 +km-ivlen: 4 +km-maclen: 0 +km-ccipkey: 3c:03:17:61:1e:88:4a:aa:01:4c:ac:6c:f8:bb:91:c3:0e:ec:57:c7:bf:07:ff:eb:49:22:f9:80:12:64:72:2a +km-scipkey: f8:00:8e:b2:dc:25:98:f1:97:00:55:28:60:a3:65:da:42:89:18:bb:40:94:53:d2:75:2a:29:e5:aa:94:1d:7a +km-civ: 24:02:76:6f +km-siv: 3b:6d:33:5a +km-cmackey: (null) +km-smackey: (null) diff --git a/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java b/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java index ad69bfeb123..2083dadc5b2 100644 --- a/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java +++ b/test/jdk/sun/security/pkcs11/tls/TestKeyMaterial.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2022, 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,7 +23,7 @@ /* * @test - * @bug 6316539 8136355 + * @bug 6316539 8136355 8294906 * @summary Known-answer-test for TlsKeyMaterial generator * @author Andreas Sterbenz * @library /test/lib .. @@ -77,6 +77,7 @@ public void main(Provider provider) throws Exception { byte[] clientRandom = null; byte[] serverRandom = null; String cipherAlgorithm = null; + String hashAlgorithm = null; // TLS1.2+ only int keyLength = 0; int expandedKeyLength = 0; int ivLength = 0; @@ -110,6 +111,8 @@ public void main(Provider provider) throws Exception { serverRandom = parse(data); } else if (line.startsWith("km-cipalg:")) { cipherAlgorithm = data; + } else if (line.startsWith("km-hashalg:")) { + hashAlgorithm = data; } else if (line.startsWith("km-keylen:")) { keyLength = Integer.parseInt(data); } else if (line.startsWith("km-explen:")) { @@ -135,14 +138,17 @@ public void main(Provider provider) throws Exception { n++; KeyGenerator kg = - KeyGenerator.getInstance("SunTlsKeyMaterial", provider); + KeyGenerator.getInstance(minor == 3 ? + "SunTls12KeyMaterial" : + "SunTlsKeyMaterial", provider); SecretKey masterKey = new SecretKeySpec(master, "TlsMasterSecret"); + // prfHashLength and prfBlockSize are ignored by PKCS11 provider TlsKeyMaterialParameterSpec spec = new TlsKeyMaterialParameterSpec(masterKey, major, minor, clientRandom, serverRandom, cipherAlgorithm, keyLength, expandedKeyLength, ivLength, macLength, - null, -1, -1); + hashAlgorithm, -1 /*ignored*/, -1 /*ignored*/); try { kg.init(spec); diff --git a/test/jdk/sun/security/pkcs11/tls/keymatdata.txt b/test/jdk/sun/security/pkcs11/tls/keymatdata.txt index 391f300007d..1d1ee636914 100644 --- a/test/jdk/sun/security/pkcs11/tls/keymatdata.txt +++ b/test/jdk/sun/security/pkcs11/tls/keymatdata.txt @@ -3646,3 +3646,37 @@ km-civ: 17:bd:47:89:54:be:04:23 km-siv: 34:8a:e8:24:84:38:c4:e1 km-cmackey: e8:f0:b5:7b:a7:cc:2f:5e:43:ef:d3:dd:4e:8c:f9:6f:51:d7:84:df km-smackey: fc:0c:77:20:c2:28:d3:11:ba:57:13:d8:0b:2d:f1:30:89:c6:35:69 +km-master: f1:05:15:45:33:be:50:d6:88:0b:03:bb:88:9b:ef:d4:3b:98:aa:40:13:71:3c:1c:d9:df:34:c7:50:75:ad:5c:0a:d4:fe:ed:d5:58:6b:ff:2b:ce:c6:12:bc:6b:7e:dc +km-major: 3 +km-minor: 3 +km-crandom: 42:f3:36:8e:9d:c9:69:3e:c1:8a:38:d3:e0:ec:2b:58:c2:e0:0c:de:4f:f3:af:51:d2:5c:bc:b2:c3:3b:1e:56 +km-srandom: 42:f3:36:8e:fa:fd:23:3e:fd:f9:bc:88:3c:98:93:f3:c3:1d:9c:2a:4a:3b:02:a7:40:d4:64:04:59:e9:65:97 +km-cipalg: AES +km-hashalg: SHA-256 +km-keylen: 16 +km-explen: 0 +km-ivlen: 4 +km-maclen: 0 +km-ccipkey: 60:7a:45:a9:6e:76:58:ea:d9:44:c5:25:f8:92:f1:26 +km-scipkey: 42:c0:ed:75:a2:51:21:7c:50:74:9d:78:9a:f7:35:2b +km-civ: a1:3c:3e:4a +km-siv: 85:ab:ee:70 +km-cmackey: (null) +km-smackey: (null) +km-master: f1:05:15:45:33:be:50:d6:88:0b:03:bb:88:9b:ef:d4:3b:98:aa:40:13:71:3c:1c:d9:df:34:c7:50:75:ad:5c:0a:d4:fe:ed:d5:58:6b:ff:2b:ce:c6:12:bc:6b:7e:dc +km-major: 3 +km-minor: 3 +km-crandom: 42:f3:36:8e:9d:c9:69:3e:c1:8a:38:d3:e0:ec:2b:58:c2:e0:0c:de:4f:f3:af:51:d2:5c:bc:b2:c3:3b:1e:56 +km-srandom: 42:f3:36:8e:fa:fd:23:3e:fd:f9:bc:88:3c:98:93:f3:c3:1d:9c:2a:4a:3b:02:a7:40:d4:64:04:59:e9:65:97 +km-cipalg: AES +km-hashalg: SHA-384 +km-keylen: 32 +km-explen: 0 +km-ivlen: 4 +km-maclen: 0 +km-ccipkey: 3c:03:17:61:1e:88:4a:aa:01:4c:ac:6c:f8:bb:91:c3:0e:ec:57:c7:bf:07:ff:eb:49:22:f9:80:12:64:72:2a +km-scipkey: f8:00:8e:b2:dc:25:98:f1:97:00:55:28:60:a3:65:da:42:89:18:bb:40:94:53:d2:75:2a:29:e5:aa:94:1d:7a +km-civ: 24:02:76:6f +km-siv: 3b:6d:33:5a +km-cmackey: (null) +km-smackey: (null) From 9eeb7415d6c5e73142a1ec559f846f2ed694be51 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 18 Apr 2023 12:58:09 +0000 Subject: [PATCH 046/217] 8295564: Norwegian Nynorsk Locale is missing formatting Reviewed-by: andrew Backport-of: b37421e7578c108df87c24c93dcbc1f358f6c257 --- .../jdk/src/classes/build/tools/cldrconverter/Bundle.java | 4 +--- test/jdk/sun/text/resources/LocaleData.cldr | 8 ++++++++ test/jdk/sun/text/resources/LocaleDataTest.java | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java index 9f262fa0106..e7874e6e3b6 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/Bundle.java @@ -197,9 +197,7 @@ Map getTargetMap() throws Exception { // parentsMap contains resources from id's parents. Map parentsMap = new HashMap<>(); for (int i = cldrBundles.length - 1; i > index; i--) { - if (!("no".equals(cldrBundles[i]) || cldrBundles[i].startsWith("no_"))) { - parentsMap.putAll(CLDRConverter.getCLDRBundle(cldrBundles[i])); - } + parentsMap.putAll(CLDRConverter.getCLDRBundle(cldrBundles[i])); } // Duplicate myMap as parentsMap for "root" so that the // fallback works. This is a hack, though. diff --git a/test/jdk/sun/text/resources/LocaleData.cldr b/test/jdk/sun/text/resources/LocaleData.cldr index da82854fcc3..bb90f4c2799 100644 --- a/test/jdk/sun/text/resources/LocaleData.cldr +++ b/test/jdk/sun/text/resources/LocaleData.cldr @@ -8395,6 +8395,14 @@ FormatData/de_AT/latn.NumberElements/12=. FormatData/fr/latn.NumberElements/11= FormatData/fr_CH/latn.NumberElements/11=. +# bug # 8295564 +FormatData/nb/latn.NumberElements/0=, +FormatData/nb/latn.NumberElements/1=\u00a0 +FormatData/no/latn.NumberElements/0=, +FormatData/no/latn.NumberElements/1=\u00a0 +FormatData/nn/latn.NumberElements/0=, +FormatData/nn/latn.NumberElements/1=\u00a0 + # tzdata2022f TimeZoneNames/en/America\/Ojinaga/1=Central Standard Time TimeZoneNames/en/America\/Chihuahua/1=Central Standard Time diff --git a/test/jdk/sun/text/resources/LocaleDataTest.java b/test/jdk/sun/text/resources/LocaleDataTest.java index 56e6f7dfd2a..a312f48ebfa 100644 --- a/test/jdk/sun/text/resources/LocaleDataTest.java +++ b/test/jdk/sun/text/resources/LocaleDataTest.java @@ -40,7 +40,7 @@ * 8145136 8145952 8164784 8037111 8081643 7037368 8178872 8185841 8190918 * 8187946 8195478 8181157 8179071 8193552 8202026 8204269 8202537 8208746 * 8209775 8221432 8227127 8230284 8231273 8233579 8234288 8250665 8255086 - * 8251317 8274658 8283277 8296715 + * 8251317 8274658 8283277 8296715 8295564 * @summary Verify locale data * @modules java.base/sun.util.resources * @modules jdk.localedata From ff675ccb587dbb2d37733522618d7312c77a807a Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 18 Apr 2023 13:00:14 +0000 Subject: [PATCH 047/217] 8297000: [jib] Add more friendly warning for proxy issues Backport-of: 0d93ab9dff04409469faa26d5cdb29c4d6488537 --- bin/jib.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/bin/jib.sh b/bin/jib.sh index aab198990cc..254f09ada1c 100644 --- a/bin/jib.sh +++ b/bin/jib.sh @@ -128,6 +128,15 @@ install_jib() { exit 1 fi fi + # Want to check the filetype using file, to see if we got served a HTML error page. + # This is sensitive to the filename containing a specific string, but good enough. + file ${installed_jib_script}.gz | grep "gzip compressed data" > /dev/null + if [ $? -ne 0 ]; then + echo "Warning: ${installed_jib_script}.gz is not a gzip file." + echo "If you are behind a proxy you may need to configure exceptions using no_proxy." + echo "The download URL was: ${jib_url}" + exit 1 + fi echo "Extracting JIB bootstrap script" rm -f "${installed_jib_script}" gunzip "${installed_jib_script}.gz" From e6c27925d23fe283a23c6adbe263658909c3739d Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Tue, 18 Apr 2023 13:07:20 +0000 Subject: [PATCH 048/217] 8299959: C2: CmpU::Value must filter overflow computation against local sub computation Backport-of: 5f66024e957e5e40ce8d5a65717ea7f82c9f0b8f --- src/hotspot/share/opto/subnode.cpp | 11 +++- .../TestRangeCheckCmpUOverflowVsSub.java | 64 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCmpUOverflowVsSub.java diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index e4e4717bd55..36ede9110cc 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -683,6 +683,9 @@ const Type* CmpUNode::Value(PhaseGVN* phase) const { if (t2 == TypeInt::INT) { // Compare to bottom? return bottom_type(); } + + const Type* t_sub = sub(t1, t2); // compare based on immediate inputs + uint in1_op = in1->Opcode(); if (in1_op == Op_AddI || in1_op == Op_SubI) { // The problem rise when result of AddI(SubI) may overflow @@ -735,13 +738,15 @@ const Type* CmpUNode::Value(PhaseGVN* phase) const { const TypeInt* tr2 = TypeInt::make(lo_tr2, hi_tr2, w); const TypeInt* cmp1 = sub(tr1, t2)->is_int(); const TypeInt* cmp2 = sub(tr2, t2)->is_int(); - // compute union, so that cmp handles all possible results from the two cases - return cmp1->meet(cmp2); + // Compute union, so that cmp handles all possible results from the two cases + const Type* t_cmp = cmp1->meet(cmp2); + // Pick narrowest type, based on overflow computation and on immediate inputs + return t_sub->filter(t_cmp); } } } - return sub(t1, t2); // Local flavor of type subtraction + return t_sub; } bool CmpUNode::is_index_range_check() const { diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCmpUOverflowVsSub.java b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCmpUOverflowVsSub.java new file mode 100644 index 00000000000..76a6d075c06 --- /dev/null +++ b/test/hotspot/jtreg/compiler/rangechecks/TestRangeCheckCmpUOverflowVsSub.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * @test + * @bug 8299959 + * @summary In CmpU::Value, the sub computation may be narrower than the overflow computation. + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressCCP -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.rangechecks.TestRangeCheckCmpUOverflowVsSub::test + * -XX:RepeatCompilation=50 + * compiler.rangechecks.TestRangeCheckCmpUOverflowVsSub +*/ + +package compiler.rangechecks; + +public class TestRangeCheckCmpUOverflowVsSub { + static int arr[] = new int[400]; + + public static void main(String[] strArr) { + for (int i = 0; i < 10; i++) { + test(); // repeat for multiple compilations + } + } + + static void test() { + for(int i = 0; i < 50_000; i++) {} //empty loop - trigger OSR faster + int val; + int zero = arr[5]; + int i = 1; + do { + for (int j = 1; j < 3; j++) { + for (int k = 2; k > i; k -= 3) { + try { + val = arr[i + 1] % k; + val = arr[i - 1] % zero; + val = arr[k - 1]; + } catch (ArithmeticException e) {} // catch div by zero + } + } + } while (++i < 3); + } +} + From 02efaf73863945b357bd8ccf6327cd8a053869d2 Mon Sep 17 00:00:00 2001 From: Aleksey Shipilev Date: Wed, 19 Apr 2023 20:12:38 +0000 Subject: [PATCH 049/217] 8269821: Remove is-queue-active check in inner loop of write_ref_array_pre_work Reviewed-by: tschatzl Backport-of: 675a9520b21e7adfded8a4bb8b1a06c1dcc6ccfb --- src/hotspot/share/gc/g1/g1BarrierSet.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.cpp b/src/hotspot/share/gc/g1/g1BarrierSet.cpp index d6e103d478e..9ffd5ed7846 100644 --- a/src/hotspot/share/gc/g1/g1BarrierSet.cpp +++ b/src/hotspot/share/gc/g1/g1BarrierSet.cpp @@ -71,12 +71,16 @@ void G1BarrierSet::enqueue(oop pre_val) { template void G1BarrierSet::write_ref_array_pre_work(T* dst, size_t count) { - if (!_satb_mark_queue_set.is_active()) return; + G1SATBMarkQueueSet& queue_set = G1BarrierSet::satb_mark_queue_set(); + if (!queue_set.is_active()) return; + + SATBMarkQueue& queue = G1ThreadLocalData::satb_mark_queue(Thread::current()); + T* elem_ptr = dst; for (size_t i = 0; i < count; i++, elem_ptr++) { T heap_oop = RawAccess<>::oop_load(elem_ptr); if (!CompressedOops::is_null(heap_oop)) { - enqueue(CompressedOops::decode_not_null(heap_oop)); + queue_set.enqueue_known_active(queue, CompressedOops::decode_not_null(heap_oop)); } } } From 6254bdf88659c9a0bbea432dd3a303fdb5495f73 Mon Sep 17 00:00:00 2001 From: Sergey Bylokhov Date: Wed, 19 Apr 2023 22:04:23 +0000 Subject: [PATCH 050/217] 8298887: On the latest macOS+XCode the Robot API may report wrong colors Reviewed-by: phh Backport-of: 50120396b6cca1219fb5dd42a11e4b29b79bd3bd --- .../macosx/native/libawt_lwawt/awt/CRobot.m | 6 +----- .../macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h | 10 +--------- .../awt/Robot/CheckCommonColors/CheckCommonColors.java | 2 +- .../java/awt/font/GlyphVector/MultiSlotFontTest.java | 2 +- 4 files changed, 4 insertions(+), 16 deletions(-) diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m index 4f495e31e36..147af2b7a7f 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CRobot.m @@ -47,10 +47,6 @@ #define k_JAVA_ROBOT_WHEEL_COUNT 1 -#if !defined(kCGBitmapByteOrder32Host) -#define kCGBitmapByteOrder32Host 0 -#endif - // In OS X, left and right mouse button share the same click count. // That is, if one starts clicking the left button rapidly and then // switches to the right button, then the click count will continue @@ -355,7 +351,7 @@ static inline void autoDelay(BOOL isMove) { 8, picWidth * sizeof(jint), picColorSpace, kCGBitmapByteOrder32Host | - kCGImageAlphaPremultipliedFirst); + kCGImageAlphaNoneSkipFirst); CGColorSpaceRelease(picColorSpace); diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h b/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h index d0312504e10..6eac8458f6c 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/QuartzSurfaceData.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2022, 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 @@ -29,14 +29,6 @@ #import #import "JNIUtilities.h" -// these flags are not defined on Tiger on PPC, so we need to make them a no-op -#if !defined(kCGBitmapByteOrder32Host) -#define kCGBitmapByteOrder32Host 0 -#endif -#if !defined(kCGBitmapByteOrder16Host) -#define kCGBitmapByteOrder16Host 0 -#endif - // NOTE : Modify the printSurfaceDataDiagnostics API if you change this enum enum SDRenderType { diff --git a/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java b/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java index 55d9b4358af..8025bc9839e 100644 --- a/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java +++ b/test/jdk/java/awt/Robot/CheckCommonColors/CheckCommonColors.java @@ -40,7 +40,7 @@ /** * @test * @key headful - * @bug 8215105 8211999 + * @bug 8215105 8211999 8298887 * @summary tests that Robot can capture the common colors without artifacts * @run main/othervm CheckCommonColors * @run main/othervm -Xcheck:jni CheckCommonColors diff --git a/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java b/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java index 65acd420345..986d4bcf5d3 100644 --- a/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java +++ b/test/jdk/java/awt/font/GlyphVector/MultiSlotFontTest.java @@ -23,7 +23,7 @@ /** * @test - * @bug 8240756 + * @bug 8240756 8298887 * @summary Non-English characters are printed with wrong glyphs on MacOS * @modules java.desktop/sun.java2d java.desktop/sun.java2d.loops java.desktop/sun.font * @requires os.family == "mac" From 52a66f91253b6f5776e63a6148d5a12735283274 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 07:46:19 +0000 Subject: [PATCH 051/217] 8268298: jdk/jfr/api/consumer/log/TestVerbosity.java fails: unexpected log message Backport-of: 06d26208c5604c0c640eff4da94ef814c2ebebf0 --- test/jdk/jdk/jfr/api/consumer/log/TestVerbosity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/jdk/jfr/api/consumer/log/TestVerbosity.java b/test/jdk/jdk/jfr/api/consumer/log/TestVerbosity.java index 9caf13cd1c0..0533a0177f3 100644 --- a/test/jdk/jdk/jfr/api/consumer/log/TestVerbosity.java +++ b/test/jdk/jdk/jfr/api/consumer/log/TestVerbosity.java @@ -42,7 +42,7 @@ * jdk.jfr.api.consumer.log.TestVerbosity trace * @run main/othervm * -Xlog:jfr+event*=debug:file=debug.log - * -XX:StartFlightRecording + * -XX:StartFlightRecording:jdk.ExecutionSample#enabled=false * jdk.jfr.api.consumer.log.TestVerbosity debug * @run main/othervm * -Xlog:jfr+event*=info:file=info.log From ef1a9ec02fa09a51ad1c486ed8c8ca6ccfd1652b Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 07:51:13 +0000 Subject: [PATCH 052/217] 8270869: G1ServiceThread may not terminate Backport-of: 7f35e5bac9925c06985f16d225f5dd9c50157d06 --- src/hotspot/share/gc/g1/g1ServiceThread.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/gc/g1/g1ServiceThread.cpp b/src/hotspot/share/gc/g1/g1ServiceThread.cpp index 7b39b7d2808..cb6b897fcb0 100644 --- a/src/hotspot/share/gc/g1/g1ServiceThread.cpp +++ b/src/hotspot/share/gc/g1/g1ServiceThread.cpp @@ -112,12 +112,10 @@ void G1ServiceThread::notify() { } void G1ServiceThread::sleep_before_next_cycle() { + MonitorLocker ml(&_monitor, Mutex::_no_safepoint_check_flag); if (should_terminate()) { return; - } - - MonitorLocker ml(&_monitor, Mutex::_no_safepoint_check_flag); - if (_task_queue.is_empty()) { + } else if (_task_queue.is_empty()) { // Sleep until new task is registered if no tasks available. log_trace(gc, task)("G1 Service Thread (wait for new tasks)"); ml.wait(0); From db3b06fd8c1e298e8ca691c4b7db0c7d2fdfa922 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 07:53:09 +0000 Subject: [PATCH 053/217] 8270434: JDI+UT: Unexpected event in JDI tests Backport-of: 8c022e2c174cca2b03e8fdf4fadad42bc11c65f1 --- .../EventIterator/nextEvent/nextevent001.java | 8 ++++--- .../methodEntryRequests/methentreq002.java | 4 ++-- .../vmTestbase/nsk/share/jdi/JDIBase.java | 21 +++++++++++++++++++ 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java index 64f98ba53bf..444382bbdb1 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, 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 @@ -320,6 +320,8 @@ private void testRun() log1(" TESTING BEGINS"); { + final String testThreadName = "thread2"; + log2("......setting up ThreadStartRequest"); ThreadStartRequest tsr = eventRManager.createThreadStartRequest(); tsr.addCountFilter(1); @@ -342,7 +344,7 @@ private void testRun() vm.resume(); log2("......waiting for ThreadStartEvent"); - getEventSet(); + getEventSetForThreadStartDeath(testThreadName); eventSets[10] = eventSet; Event receivedEvent = eventIterator.nextEvent(); @@ -357,7 +359,7 @@ private void testRun() vm.resume(); log2("......waiting for ThreadDeathEvent"); - getEventSet(); + getEventSetForThreadStartDeath(testThreadName); eventSets[9] = eventSet; receivedEvent = eventIterator.nextEvent(); if ( !(receivedEvent instanceof ThreadDeathEvent) ) { diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodEntryRequests/methentreq002.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodEntryRequests/methentreq002.java index 691ce87e0d3..6b6fd054412 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodEntryRequests/methentreq002.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventRequestManager/methodEntryRequests/methentreq002.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2021, 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 @@ -266,7 +266,7 @@ private void testRun() for (int i = 0; ; i++) { vm.resume(); - breakpointForCommunication(); + breakpointForCommunication(debuggeeName); int instruction = ((IntegerValue) (debuggeeClass.getValue(debuggeeClass.fieldByName("instruction")))).value(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java index 4b2f1381828..da8c49119b7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java @@ -197,4 +197,25 @@ protected void breakpointForCommunication() throws JDITestRuntimeException { throw new JDITestRuntimeException("** event '" + event + "' IS NOT a breakpoint **"); } + // Similar to breakpointForCommunication, but skips Locatable events from unexpected locations. + // It's useful for cases when enabled event requests can cause notifications from system threads + // (like MethodEntryRequest, MethodExitRequest). + protected void breakpointForCommunication(String debuggeeName) throws JDITestRuntimeException { + log2("breakpointForCommunication"); + while (true) { + getEventSet(); + + Event event = eventIterator.nextEvent(); + if (event instanceof BreakpointEvent) { + return; + } + if (EventFilters.filtered(event, debuggeeName)) { + log2(" got unexpected event: " + event + ", skipping"); + eventSet.resume(); + } else { + throw new JDITestRuntimeException("** event '" + event + "' IS NOT a breakpoint **"); + } + } + } + } From 40b1dafaa3547da534b2409fbd81a33070b626a8 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 07:56:31 +0000 Subject: [PATCH 054/217] 8273909: vmTestbase/nsk/jdi/Event/request/request001 can still fail with "ERROR: new event is not ThreadStartEvent" Backport-of: 5fde4b64e25a3b3a4c01c57064624b9f930a1324 --- .../nsk/jdi/Event/request/request001.java | 2 -- .../EventIterator/nextEvent/nextevent001.java | 2 -- .../addThreadFilter/addthreadfilter001.java | 3 --- .../vmTestbase/nsk/share/jdi/JDIBase.java | 20 ++++++++++--------- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Event/request/request001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Event/request/request001.java index 1e9560e712f..5034a5f5ee0 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/Event/request/request001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/Event/request/request001.java @@ -335,7 +335,6 @@ private void testRun() log2("......setting up ThreadStartRequest"); ThreadStartRequest tsr = eventRManager.createThreadStartRequest(); - tsr.addCountFilter(1); tsr.setSuspendPolicy(EventRequest.SUSPEND_ALL); tsr.putProperty("number", "ThreadStartRequest"); tsr.enable(); @@ -344,7 +343,6 @@ private void testRun() log2("......setting up ThreadDeathRequest"); ThreadDeathRequest tdr = eventRManager.createThreadDeathRequest(); - tdr.addCountFilter(1); tdr.setSuspendPolicy(EventRequest.SUSPEND_ALL); tsr.putProperty("number", "ThreadDeathRequest"); tdr.enable(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java index 444382bbdb1..1c3a03f4fe7 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventIterator/nextEvent/nextevent001.java @@ -324,7 +324,6 @@ private void testRun() log2("......setting up ThreadStartRequest"); ThreadStartRequest tsr = eventRManager.createThreadStartRequest(); - tsr.addCountFilter(1); tsr.setSuspendPolicy(EventRequest.SUSPEND_ALL); tsr.putProperty("number", "ThreadStartRequest"); tsr.enable(); @@ -333,7 +332,6 @@ private void testRun() log2("......setting up ThreadDeathRequest"); ThreadDeathRequest tdr = eventRManager.createThreadDeathRequest(); - tdr.addCountFilter(1); tdr.setSuspendPolicy(EventRequest.SUSPEND_ALL); tsr.putProperty("number", "ThreadDeathRequest"); tdr.enable(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter001.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter001.java index 573ef44f867..5dc0293b848 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter001.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ThreadDeathRequest/addThreadFilter/addthreadfilter001.java @@ -279,21 +279,18 @@ private void testRun() log2("......setting up ThreadDeathRequest"); ThreadDeathRequest tdr1 = eventRManager.createThreadDeathRequest(); // tdr1.addThreadFilter(mainThread); - tdr1.addCountFilter(1); tdr1.setSuspendPolicy(EventRequest.SUSPEND_ALL); tdr1.putProperty("number", "ThreadDeathRequest1"); tdr1.enable(); ThreadDeathRequest tdr2 = eventRManager.createThreadDeathRequest(); // tsr2.addThreadFilter(mainThread); - tdr2.addCountFilter(1); tdr2.setSuspendPolicy(EventRequest.SUSPEND_ALL); tdr2.putProperty("number", "ThreadDeathRequest2"); tdr2.enable(); ThreadDeathRequest tdr3 = eventRManager.createThreadDeathRequest(); tdr3.addThreadFilter(testThread); - tdr3.addCountFilter(1); tdr3.setSuspendPolicy(EventRequest.SUSPEND_ALL); tdr3.putProperty("number", "ThreadDeathRequest3"); tdr3.enable(); diff --git a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java index da8c49119b7..d20a084a632 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/share/jdi/JDIBase.java @@ -157,27 +157,29 @@ protected final void getEventSet() throws JDITestRuntimeException { // we can get the events from system threads unexpected for tests. // The method skips ThreadStartEvent/ThreadDeathEvent events // for all threads except the expected one. + // Note: don't limit ThreadStartRequest/ThreadDeathRequest request by addCountFilter(), + // as it limits the requested event to be reported at most once. protected void getEventSetForThreadStartDeath(String threadName) throws JDITestRuntimeException { - boolean gotDesiredEvent = false; - while (!gotDesiredEvent) { + while (true) { getEventSet(); Event event = eventIterator.nextEvent(); if (event instanceof ThreadStartEvent evt) { if (evt.thread().name().equals(threadName)) { - gotDesiredEvent = true; - } else { - log2("Got ThreadStartEvent for wrong thread: " + event); + break; } + log2("Got ThreadStartEvent for '" + evt.thread().name() + + "' instead of '" + threadName + "', skipping"); } else if (event instanceof ThreadDeathEvent evt) { if (evt.thread().name().equals(threadName)) { - gotDesiredEvent = true; - } else { - log2("Got ThreadDeathEvent for wrong thread: " + event); + break; } + log2("Got ThreadDeathEvent for '" + evt.thread().name() + + "' instead of '" + threadName + "', skipping"); } else { // not ThreadStartEvent nor ThreadDeathEvent - gotDesiredEvent = true; + break; } + eventSet.resume(); } // reset the iterator before return eventIterator = eventSet.eventIterator(); From 37c506166307703aed75454cb7e29cc6a183647a Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 07:58:19 +0000 Subject: [PATCH 055/217] 8282704: runtime/Thread/StopAtExit.java may leak memory Backport-of: 3f923b82c31325504430b50dee262fd460004e7b --- .../jtreg/runtime/Thread/StopAtExit.java | 69 ++++++++++++++++++- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/test/hotspot/jtreg/runtime/Thread/StopAtExit.java b/test/hotspot/jtreg/runtime/Thread/StopAtExit.java index 22550093202..b997890e347 100644 --- a/test/hotspot/jtreg/runtime/Thread/StopAtExit.java +++ b/test/hotspot/jtreg/runtime/Thread/StopAtExit.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2022, 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,11 +23,13 @@ /** * @test - * @bug 8167108 8266130 + * @bug 8167108 8266130 8282704 * @summary Stress test java.lang.Thread.stop() at thread exit. + * @modules java.base/java.lang:open * @run main/othervm StopAtExit */ +import java.lang.reflect.Method; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -38,6 +40,10 @@ public class StopAtExit extends Thread { public CountDownLatch exitSyncObj = new CountDownLatch(1); public CountDownLatch startSyncObj = new CountDownLatch(1); + public StopAtExit(ThreadGroup group, Runnable target) { + super(group, target); + } + @Override public void run() { try { @@ -72,11 +78,18 @@ public static void main(String[] args) { System.out.println("About to execute for " + timeMax + " seconds."); long count = 0; + long manualDestroyCnt = 0; + long manualTerminateCnt = 0; long start_time = System.currentTimeMillis(); while (System.currentTimeMillis() < start_time + (timeMax * 1000)) { count++; - StopAtExit thread = new StopAtExit(); + // Use my own ThreadGroup so the thread count is known and make + // it a daemon ThreadGroup so it is automatically destroyed when + // the thread is terminated. + ThreadGroup myTG = new ThreadGroup("myTG-" + count); + myTG.setDaemon(true); + StopAtExit thread = new StopAtExit(myTG, null); thread.start(); try { // Wait for the worker thread to get going. @@ -107,9 +120,52 @@ public static void main(String[] args) { } catch (InterruptedException e) { throw new Error("Unexpected: " + e); } + // This stop() call happens after the join() so it should do + // nothing, but let's make sure. thread.stop(); + + if (myTG.activeCount() != 0) { + // If the ThreadGroup still has a count, then the thread + // received the async exception while in exit() so we need + // to do a manual terminate. + manualTerminateCnt++; + try { + threadTerminated(myTG, thread); + } catch (Exception e) { + throw new Error("threadTerminated() threw unexpected: " + e); + } + int activeCount = myTG.activeCount(); + if (activeCount != 0) { + throw new Error("threadTerminated() did not clean up " + + "worker thread: count=" + activeCount); + } + if (!myTG.isDestroyed()) { + throw new Error("threadTerminated() did not destroy " + + myTG.getName()); + } + } else if (!myTG.isDestroyed()) { + // If the ThreadGroup does not have a count, but is not + // yet destroyed, then the thread received the async + // exception while the thread was in the later stages of + // its threadTerminated() call so we need to do a manual + // destroy. + manualDestroyCnt++; + try { + myTG.destroy(); + } catch (Exception e) { + throw new Error("myTG.destroy() threw unexpected: " + e); + } + } } + if (manualDestroyCnt != 0) { + System.out.println("Manually destroyed ThreadGroup " + + manualDestroyCnt + " times."); + } + if (manualTerminateCnt != 0) { + System.out.println("Manually terminated Thread " + + manualTerminateCnt + " times."); + } System.out.println("Executed " + count + " loops in " + timeMax + " seconds."); @@ -120,6 +176,13 @@ public static void main(String[] args) { } } + static void threadTerminated(ThreadGroup group, Thread thread) throws Exception { + // ThreadGroup.threadTerminated() is package private: + Method method = ThreadGroup.class.getDeclaredMethod("threadTerminated", Thread.class); + method.setAccessible(true); + method.invoke(group, thread); + } + public static void usage() { System.err.println("Usage: " + PROG_NAME + " [time_max]"); System.err.println("where:"); From c2b379fc124f1b7d76865631b42b32bcc9875c45 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:00:07 +0000 Subject: [PATCH 056/217] 8277775: Fixup bugids in RemoveDropTargetCrashTest.java - add 4357905 Backport-of: 22347e46f7e66a864ea987fa084c44792cae2e6a --- .../RemoveDropTargetCrashTest/RemoveDropTargetCrashTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/jdk/java/awt/dnd/RemoveDropTargetCrashTest/RemoveDropTargetCrashTest.java b/test/jdk/java/awt/dnd/RemoveDropTargetCrashTest/RemoveDropTargetCrashTest.java index 2534ee3fbfa..4741e0595e1 100644 --- a/test/jdk/java/awt/dnd/RemoveDropTargetCrashTest/RemoveDropTargetCrashTest.java +++ b/test/jdk/java/awt/dnd/RemoveDropTargetCrashTest/RemoveDropTargetCrashTest.java @@ -60,7 +60,7 @@ /** * @test * @key headful - * @bug 4393148 8136999 8186263 8224632 + * @bug 4393148 4357905 8136999 8186263 8224632 * @summary tests that removal of the drop target or disposal of frame during * drop processing doesn't cause crash * @run main/timeout=300 RemoveDropTargetCrashTest RUN_PROCESS From fc9c2decaafd626c9444adbda9e7c6bb84eccc8c Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:01:03 +0000 Subject: [PATCH 057/217] 8289949: Improve test coverage for XPath: operators Backport-of: f6b636015573f9b88133efba2f87bed80f463a96 --- .../unittest/xpath/XPathOperatorExpTest.java | 141 ++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 test/jaxp/javax/xml/jaxp/unittest/xpath/XPathOperatorExpTest.java diff --git a/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathOperatorExpTest.java b/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathOperatorExpTest.java new file mode 100644 index 00000000000..affdfcf4bdf --- /dev/null +++ b/test/jaxp/javax/xml/jaxp/unittest/xpath/XPathOperatorExpTest.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2022, 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 xpath; + +import org.testng.Assert; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.w3c.dom.Document; + +import javax.xml.xpath.XPathExpressionException; + +/* + * @test + * @bug 8289949 + * @summary Tests the XPath operator expressions + * @library /javax/xml/jaxp/unittest + * + * @run testng xpath.XPathOperatorExpTest + */ +public class XPathOperatorExpTest extends XPathTestBase { + private static final Document doc = getDocument(); + + /* + * DataProvider for testing the XPath operator expressions. + * Data columns: + * see parameters of the test "testOperatorExp" + */ + @DataProvider(name = "operatorExpTestCases") + public Object[][] getOperatorExp() { + return new Object[][]{ + // boolean and relational operators: or, and, =, !=, <, <=, >, >= + {"string(//Customer[Age > 0]/Name)", "name2"}, + {"string(//Customer[Age < 0]/Name)", "name3"}, + {"string(//Customer[Age = 0]/Name)", "name1"}, + {"count(//Customer[Age >= 0 and Age <= 0])", 1}, + {"count(//Customer[Age >= 0][Age <= 0])", 1}, + {"count(//Customer[Age > 0 or Age < 0])", 2}, + {"count(//Customer[Age != 0])", 2}, + + // arithmetic operators: +, -, *, div, mod + {"string(//Customer[last() div 2]/Name)", "name1"}, + {"string(//Customer[position() * 2 > last()]/Name)", "name2"}, + {"string(//Customer[position() + 1 < last()]/Name)", "name1"}, + {"string(//Customer[last() - 1]/Name)", "name2"}, + {"string(//Customer[last() mod 2]/Name)", "name1"}, + + // union operator: | + {"count(//Customer[Name='name1'] | //Customer[Name='name2'])", + 2}, + {"count(//Customer[Name='name1'] | //Customer[Name='name2'] |" + + " //Customer[Name='name3'])", 3}, + + // operator precedence + {"1 + 2 * 3 + 3", 10.0}, + {"1 + 1 div 2 + 2", 3.5}, + {"1 + 1 mod 2 + 2", 4.0}, + {"1 * 1 mod 2 div 2", 0}, + {"1 * (1 mod 2) div 2", 0.5}, + {"(1 + 2) * (3 + 3)", 18.0}, + {"(1 + 2) div (3 + 3)", 0.5}, + {"1 - 2 < 3 + 3", true}, + {"1 * 2 >= 3 div 3", true}, + {"3 > 2 > 1", false}, + {"3 > (2 > 1)", true}, + {"3 > 2 = 1", true}, + {"1 = 3 > 2", true}, + {"1 = 2 or 1 <= 2 and 2 != 2", false}, + }; + } + + /* + * DataProvider for testing XPathExpressionException being thrown on + * invalid operator usage. + * Data columns: + * see parameters of the test "testExceptionOnEval" + */ + @DataProvider(name = "exceptionExpTestCases") + public Object[][] getExceptionExp() { + return new Object[][]{ + // invalid operators + {"string(//Customer[last() / 2]/Name)"}, + {"string(//Customer[last() % 2]/Name)"}, + {"count(//Customer[Name='name1'] & //Customer[Name='name2'])"}, + {"count(//Customer[Name='name1'] && //Customer[Name='name2'])"}, + {"count(//Customer[Name='name1'] || //Customer[Name='name2'])"}, + + // union operator only works for node-sets + {"//Customer[Name='name1'] | string(//Customer[Name='name2']))"}, + }; + } + + /** + * Verifies that the result of evaluating XPath operators matches the + * expected result. + * + * @param exp XPath expression + * @param expected expected result + * @throws Exception if test fails + */ + @Test(dataProvider = "operatorExpTestCases") + void testOperatorExp(String exp, Object expected) throws Exception { + if (expected instanceof Double d) { + testExp(doc, exp, d, Double.class); + } else if (expected instanceof String s) { + testExp(doc, exp, s, String.class); + } else if (expected instanceof Boolean b) { + testExp(doc, exp, b, Boolean.class); + } + } + + /** + * Verifies that XPathExpressionException is thrown on xpath evaluation. + * + * @param exp XPath expression + */ + @Test(dataProvider = "exceptionExpTestCases") + void testExceptionOnEval(String exp) { + Assert.assertThrows(XPathExpressionException.class, () -> testEval(doc, + exp)); + } +} From ccc0690ea4c8d15f1631ca34a3f1ca24a43a9236 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:04:02 +0000 Subject: [PATCH 058/217] 8285635: javax/swing/JRootPane/DefaultButtonTest.java failed with Default Button not pressed for L&F: com.sun.java.swing.plaf.motif.MotifLookAndFeel Backport-of: 79c0092125ef01e2980f8072d7b295ce0c1a6077 --- test/jdk/javax/swing/JRootPane/DefaultButtonTest.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java b/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java index cff2ea73c93..560c5d82331 100644 --- a/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java +++ b/test/jdk/javax/swing/JRootPane/DefaultButtonTest.java @@ -89,6 +89,12 @@ public void runTest() throws Exception { buttonPressed = false; String lafName = laf.getClassName(); System.out.println("Testing L&F: " + lafName); + + // Ignore obsolete/deprecated Motif + if (lafName.contains("Motif")) { + System.out.println("Skipped Motif"); + continue; + } SwingUtilities.invokeAndWait(() -> { setLookAndFeel(lafName); createUI(); From ea994ccbd2be9b209473a3934947683af438ff8d Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:08:16 +0000 Subject: [PATCH 059/217] 8271519: java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java failed with "Total [200] - Expected [400]" Backport-of: 9f94cbec51df7556d34fffa810e59dd9eb8521df --- .../SequencedEvent/MultipleContextsFunctionalTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/jdk/java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java b/test/jdk/java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java index 278e862421d..9af56ba044b 100644 --- a/test/jdk/java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java +++ b/test/jdk/java/awt/event/SequencedEvent/MultipleContextsFunctionalTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2022, 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 @@ -35,8 +35,8 @@ import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.atomic.AtomicReference; import javax.swing.JButton; import javax.swing.JFrame; @@ -55,7 +55,7 @@ public final class MultipleContextsFunctionalTest { private static final int CHECK_LAPSE = 100; private static final int MAX_COUNT = MAX_TIME / INTERVAL; private static final int EXPECTED = MAX_COUNT * NUM_WINDOW; - private static final List WINDOWS = new ArrayList(); + private static final List WINDOWS = new CopyOnWriteArrayList<>(); public static void main(String[] args) { for (int i = 0; i < NUM_WINDOW; i++) { @@ -126,7 +126,7 @@ public void run() { private static final class TestWindow extends JFrame implements ActionListener { private final JButton btn; - private int counter = 0; + private volatile int counter = 0; private final Timer t; TestWindow(final int num) { From 49aab4b7b88a7d78376aa36f9599efec2e40a315 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:13:06 +0000 Subject: [PATCH 060/217] 8298488: [macos13] tools/jpackage tests failing with "Exit code: 137" on macOS Reviewed-by: mdoerr Backport-of: 8962c723a8ae62a8638e9e0a89c20001aea1549a --- .../classes/jdk/jpackage/internal/MacAppImageBuilder.java | 2 +- test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java index 4e0732a3567..cd21c8110a3 100644 --- a/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java +++ b/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppImageBuilder.java @@ -374,7 +374,7 @@ private void doSigning(Map params) ENTITLEMENTS.fetchFrom(params)); } restoreKeychainList(params); - } else if (Platform.isArmMac()) { + } else if (Platform.isMac()) { signAppBundle(params, root, "-", null, null); } else { // Calling signAppBundle() without signingIdentity will result in diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java index 52b89f568e3..1907c074504 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/TKit.java @@ -178,10 +178,6 @@ public static boolean isOSX() { return (OS.contains("mac")); } - public static boolean isArmMac() { - return (isOSX() && "aarch64".equals(System.getProperty("os.arch"))); - } - public static boolean isLinux() { return ((OS.contains("nix") || OS.contains("nux"))); } From 05e91bb7d423252ccdb302f3ae169d0e4642b939 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:14:52 +0000 Subject: [PATCH 061/217] 8296318: use-def assert: special case undetected loops nested in infinite loops Backport-of: 736fcd49f7cd3aa6f226b2e088415eaf05f97ee8 --- src/hotspot/share/opto/block.cpp | 8 ++- src/hotspot/share/opto/cfgnode.cpp | 41 ++++++++++++ src/hotspot/share/opto/cfgnode.hpp | 4 ++ src/hotspot/share/opto/loopnode.cpp | 25 +------- .../TestUndetectedLoopInInfiniteLoop.java | 62 +++++++++++++++++++ 5 files changed, 115 insertions(+), 25 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestUndetectedLoopInInfiniteLoop.java diff --git a/src/hotspot/share/opto/block.cpp b/src/hotspot/share/opto/block.cpp index 648ac5c671b..c649786872b 100644 --- a/src/hotspot/share/opto/block.cpp +++ b/src/hotspot/share/opto/block.cpp @@ -1378,7 +1378,13 @@ void PhaseCFG::verify() const { } } } - assert(is_loop || block->find_node(def) < j, "uses must follow definitions"); + // Uses must be before definition, except if: + // - We are in some kind of loop we already detected + // - We are in infinite loop, where Region may not have been turned into LoopNode + assert(block->find_node(def) < j || + is_loop || + (n->is_Phi() && block->head()->as_Region()->is_in_infinite_subgraph()), + "uses must follow definitions (except in loops)"); } } } diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp index 1d277d1124b..5323a4427a0 100644 --- a/src/hotspot/share/opto/cfgnode.cpp +++ b/src/hotspot/share/opto/cfgnode.cpp @@ -393,6 +393,47 @@ bool RegionNode::is_unreachable_from_root(const PhaseGVN* phase) const { return true; // The Region node is unreachable - it is dead. } +#ifdef ASSERT +// Is this region in an infinite subgraph? +// (no path to root except through false NeverBranch exit) +bool RegionNode::is_in_infinite_subgraph() { + ResourceMark rm; + Unique_Node_List worklist; + worklist.push(this); + return RegionNode::are_all_nodes_in_infinite_subgraph(worklist); +} + +// Are all nodes in worklist in infinite subgraph? +// (no path to root except through false NeverBranch exit) +// worklist is directly used for the traversal +bool RegionNode::are_all_nodes_in_infinite_subgraph(Unique_Node_List& worklist) { + // BFS traversal down the CFG, except through NeverBranch exits + for (uint i = 0; i < worklist.size(); ++i) { + Node* n = worklist.at(i); + assert(n->is_CFG(), "only traverse CFG"); + if (n->is_Root()) { + // Found root -> there was an exit! + return false; + } else if (n->is_NeverBranch()) { + // Only follow the loop-internal projection, not the NeverBranch exit + ProjNode* proj = n->as_NeverBranch()->proj_out_or_null(0); + assert(proj != nullptr, "must find loop-internal projection of NeverBranch"); + worklist.push(proj); + } else { + // Traverse all CFG outputs + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* use = n->fast_out(i); + if (use->is_CFG()) { + worklist.push(use); + } + } + } + } + // No exit found for any loop -> all are infinite + return true; +} +#endif //ASSERT + bool RegionNode::try_clean_mem_phi(PhaseGVN *phase) { // Incremental inlining + PhaseStringOpts sometimes produce: // diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 0f754aee453..28634d4f065 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -90,6 +90,10 @@ class RegionNode : public Node { PhiNode* has_unique_phi() const; // returns the unique phi user, or NULL // Is this region node unreachable from root? bool is_unreachable_region(const PhaseGVN* phase); +#ifdef ASSERT + bool is_in_infinite_subgraph(); + static bool are_all_nodes_in_infinite_subgraph(Unique_Node_List& worklist); +#endif //ASSERT virtual int Opcode() const; virtual uint size_of() const { return sizeof(*this); } virtual bool pinned() const { return (const Node*)in(0) == this; } diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index f26df6f239b..1a9af74b218 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -3704,30 +3704,7 @@ bool PhaseIdealLoop::only_has_infinite_loops() { assert(head->is_Region(), ""); worklist.push(head); } - // BFS traversal down the CFG, except through NeverBranch exits - for (uint i = 0; i < worklist.size(); ++i) { - Node* n = worklist.at(i); - assert(n->is_CFG(), "only traverse CFG"); - if (n->is_Root()) { - // Found root -> there was an exit! - return false; - } else if (n->is_NeverBranch()) { - // Only follow the loop-internal projection, not the NeverBranch exit - ProjNode* proj = n->as_NeverBranch()->proj_out_or_null(0); - assert(proj != nullptr, "must find loop-internal projection of NeverBranch"); - worklist.push(proj); - } else { - // Traverse all CFG outputs - for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { - Node* use = n->fast_out(i); - if (use->is_CFG()) { - worklist.push(use); - } - } - } - } - // No exit found for any loop -> all are infinite - return true; + return RegionNode::are_all_nodes_in_infinite_subgraph(worklist); } #endif diff --git a/test/hotspot/jtreg/compiler/loopopts/TestUndetectedLoopInInfiniteLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestUndetectedLoopInInfiniteLoop.java new file mode 100644 index 00000000000..868a9f27d56 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestUndetectedLoopInInfiniteLoop.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2022, 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. + */ + +/* + * @test + * @bug 8296318 + * @summary Loops inside infinite loops may not be detected, thus a region may still + * be the loop head, even if it is not a LoopNode. + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,TestUndetectedLoopInInfiniteLoop::test* + * -XX:PerMethodTrapLimit=0 + * TestUndetectedLoopInInfiniteLoop + */ + + +public class TestUndetectedLoopInInfiniteLoop { + public static void main (String[] args) { + test(true, false); + } + public static void test(boolean flag, boolean flag2) { + int x = 0; + if (flag2) { // runtime check, avoid infinite loop + while (true) { // infinite loop (no exit) + if (flag) { + x++; + } + do { // inner loop + // assert for this block + // Region + // Phi -> SubI -> XorI ---> Phi + x = (x - 1) ^ 1; + // Problem: this looks like a loop, but we have no LoopNode + // We have no LoopNode, because this is all in an infinite + // loop, and during PhaseIdealLoop::build_loop_tree we do not + // attach the loops of an infinite loop to the loop tree, + // and hence we do not get to call beautify_loop on these loops + // which would have turned the Region into a LoopNode. + } while (x < 0); + } + } + } +} From 1fe89116cb0b57deab3fbd1f712b1e70da8a428c Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:18:20 +0000 Subject: [PATCH 062/217] 8299259: C2: Div/Mod nodes without zero check could be split through iv phi of loop resulting in SIGFPE Backport-of: 8b0133f2760f67cd968528c041a600408cc26978 --- src/hotspot/share/opto/loopnode.hpp | 3 + src/hotspot/share/opto/loopopts.cpp | 53 ++++-- .../splitif/TestSplitDivisionThroughPhi.java | 160 ++++++++++++++++++ 3 files changed, 202 insertions(+), 14 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/splitif/TestSplitDivisionThroughPhi.java diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index ebc3bd1dbf8..0db6d088145 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -1506,6 +1506,9 @@ class PhaseIdealLoop : public PhaseTransform { void try_move_store_after_loop(Node* n); bool identical_backtoback_ifs(Node *n); bool can_split_if(Node *n_ctrl); + bool cannot_split_division(const Node* n, const Node* region) const; + static bool is_divisor_counted_loop_phi(const Node* divisor, const Node* loop); + bool loop_phi_backedge_type_contains_zero(const Node* phi_divisor, const Type* zero) const; // Determine if a method is too big for a/another round of split-if, based on // a magic (approximate) ratio derived from the equally magic constant 35000, diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index 358ce5b34aa..cd214febde1 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -61,19 +61,8 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { return NULL; } - // Bail out if 'n' is a Div or Mod node whose zero check was removed earlier (i.e. control is NULL) and its divisor is an induction variable - // phi p of a trip-counted (integer) loop whose inputs could be zero (include zero in their type range). p could have a more precise type - // range that does not necessarily include all values of its inputs. Since each of these inputs will be a divisor of the newly cloned nodes - // of 'n', we need to bail out of one of these divisors could be zero (zero in its type range). - if ((n->Opcode() == Op_DivI || n->Opcode() == Op_ModI) && n->in(0) == NULL - && region->is_CountedLoop() && n->in(2) == region->as_CountedLoop()->phi()) { - Node* phi = region->as_CountedLoop()->phi(); - for (uint i = 1; i < phi->req(); i++) { - if (_igvn.type(phi->in(i))->filter_speculative(TypeInt::ZERO) != Type::TOP) { - // Zero could be a possible value but we already removed the zero check. Bail out to avoid a possible division by zero at a later point. - return NULL; - } - } + if (cannot_split_division(n, region)) { + return NULL; } int wins = 0; @@ -225,6 +214,42 @@ Node* PhaseIdealLoop::split_thru_phi(Node* n, Node* region, int policy) { return phi; } +// Return true if 'n' is a Div or Mod node (without zero check If node which was removed earlier) with a loop phi divisor +// of a trip-counted (integer or long) loop with a backedge input that could be zero (include zero in its type range). In +// this case, we cannot split the division to the backedge as it could freely float above the loop exit check resulting in +// a division by zero. This situation is possible because the type of an increment node of an iv phi (trip-counter) could +// include zero while the iv phi does not (see PhiNode::Value() for trip-counted loops where we improve types of iv phis). +// We also need to check other loop phis as they could have been created in the same split-if pass when applying +// PhaseIdealLoop::split_thru_phi() to split nodes through an iv phi. +bool PhaseIdealLoop::cannot_split_division(const Node* n, const Node* region) const { + const Type* zero; + switch (n->Opcode()) { + case Op_DivI: + case Op_ModI: + zero = TypeInt::ZERO; + break; + case Op_DivL: + case Op_ModL: + zero = TypeLong::ZERO; + break; + default: + return false; + } + + assert(n->in(0) == NULL, "divisions with zero check should already have bailed out earlier in split-if"); + Node* divisor = n->in(2); + return is_divisor_counted_loop_phi(divisor, region) && + loop_phi_backedge_type_contains_zero(divisor, zero); +} + +bool PhaseIdealLoop::is_divisor_counted_loop_phi(const Node* divisor, const Node* loop) { + return loop->is_BaseCountedLoop() && divisor->is_Phi() && divisor->in(0) == loop; +} + +bool PhaseIdealLoop::loop_phi_backedge_type_contains_zero(const Node* phi_divisor, const Type* zero) const { + return _igvn.type(phi_divisor->in(LoopNode::LoopBackControl))->filter_speculative(zero) != Type::TOP; +} + //------------------------------dominated_by------------------------------------ // Replace the dominated test with an obvious true or false. Place it on the // IGVN worklist for later cleanup. Move control-dependent data Nodes on the diff --git a/test/hotspot/jtreg/compiler/splitif/TestSplitDivisionThroughPhi.java b/test/hotspot/jtreg/compiler/splitif/TestSplitDivisionThroughPhi.java new file mode 100644 index 00000000000..f9dd8b2dcb6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/splitif/TestSplitDivisionThroughPhi.java @@ -0,0 +1,160 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/** +* @test +* @key stress randomness +* @bug 8299259 +* @requires vm.compiler2.enabled +* @summary Test various cases of divisions/modulo which should not be split through iv phis. +* @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:LoopUnrollLimit=0 -XX:+StressGCM -XX:StressSeed=884154126 +* -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivisionThroughPhi::* +* compiler.splitif.TestSplitDivisionThroughPhi +*/ + +/** +* @test +* @key stress randomness +* @bug 8299259 +* @requires vm.compiler2.enabled +* @summary Test various cases of divisions/modulo which should not be split through iv phis. +* @run main/othervm -Xbatch -XX:+UnlockDiagnosticVMOptions -XX:LoopUnrollLimit=0 -XX:+StressGCM +* -XX:CompileCommand=compileonly,compiler.splitif.TestSplitDivisionThroughPhi::* +* compiler.splitif.TestSplitDivisionThroughPhi +*/ + +package compiler.splitif; + +public class TestSplitDivisionThroughPhi { + static int iFld; + static long lFld; + static boolean flag; + + + public static void main(String[] strArr) { + for (int i = 0; i < 5000; i++) { + testPushDivIThruPhi(); + testPushDivIThruPhiInChain(); + testPushModIThruPhi(); + testPushModIThruPhiInChain(); + testPushDivLThruPhi(); + testPushDivLThruPhiInChain(); + testPushModLThruPhi(); + testPushModLThruPhiInChain(); + } + } + + // Already fixed by JDK-8248552. + static void testPushDivIThruPhi() { + for (int i = 10; i > 1; i -= 2) { + // The Div node is only split in later loop opts phase because the zero divisor check is only removed + // in IGVN after the first loop opts phase. + // + // iv phi i type: [2..10] + // When splitting the DivI through the iv phi, it ends up on the back edge with the trip count decrement + // as input which has type [0..8]. We end up executing a division by zero on the last iteration because + // the DivI it is not pinned to the loop exit test and can freely float above the loop exit check. + iFld = 10 / i; + } + } + + // Same as above but with an additional Mul node between the iv phi and the Div node. Both nodes are split through + // the iv phi in one pass of Split If. + static void testPushDivIThruPhiInChain() { + for (int i = 10; i > 1; i -= 2) { + // Empty one iteration loop which is only removed after split if in first loop opts phase. This prevents + // that the Mul node is already split through the iv phi while the Div node cannot be split yet due to + // the zero divisor check which can only be removed in the IGVN after the first loop opts pass. + for (int j = 0; j < 1; j++) { + } + iFld = 10 / (i * 100); + } + } + + // Already fixed by JDK-8248552. + static void testPushModIThruPhi() { + for (int i = 10; i > 1; i -= 2) { + iFld = 10 / i; + } + } + + // Same as above but with ModI. + static void testPushModIThruPhiInChain() { + for (int i = 10; i > 1; i -= 2) { + for (int j = 0; j < 1; j++) { + } + iFld = 10 / (i * 100); + } + } + + // Long cases only trigger since JDK-8256655. + + // Same as above but with DivL. + static void testPushDivLThruPhi() { + for (long i = 10; i > 1; i -= 2) { + lFld = 10L / i; + + // Loop that is not removed such that we do not transform the outer LongCountedLoop (only done if innermost) + for (int j = 0; j < 10; j++) { + flag = !flag; + } + } + } + + // Same as above but with DivL. + static void testPushDivLThruPhiInChain() { + for (long i = 10; i > 1; i -= 2) { + for (int j = 0; j < 1; j++) { + } + lFld = 10L / (i * 100L); + + for (int j = 0; j < 10; j++) { + flag = !flag; + } + } + } + + // Same as above but with ModL + static void testPushModLThruPhi() { + for (long i = 10; i > 1; i -= 2) { + lFld = 10L % i; + + for (int j = 0; j < 10; j++) { + flag = !flag; + } + } + } + + // Same as above but with ModL + static void testPushModLThruPhiInChain() { + for (long i = 10; i > 1; i -= 2) { + for (int j = 0; j < 1; j++) { + } + lFld = 10L % (i * 100L); + + for (int j = 0; j < 10; j++) { + flag = !flag; + } + } + } +} From d21597aec91bbd41960923385f6a1feb31f14a0c Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:20:41 +0000 Subject: [PATCH 063/217] 8299179: ArrayFill with store on backedge needs to reduce length by 1 Backport-of: d716ec5d3034240b7dd0aed86d9bb371bc3e5f5a --- src/hotspot/share/opto/loopTransform.cpp | 20 ++ .../loopopts/TestBackedgeLoadArrayFill.jasm | 178 ++++++++++++++ .../TestBackedgeLoadArrayFillMain.java | 231 ++++++++++++++++++ 3 files changed, 429 insertions(+) create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFill.jasm create mode 100644 test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFillMain.java diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index f7e7073dd90..b6262332708 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -3947,6 +3947,19 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) { Node* len = new SubINode(head->limit(), head->init_trip()); _igvn.register_new_node_with_optimizer(len); + // If the store is on the backedge, it is not executed in the last + // iteration, and we must subtract 1 from the len. + Node* backedge = head->loopexit()->proj_out(1); + if (store->in(0) == backedge) { + len = new SubINode(len, _igvn.intcon(1)); + _igvn.register_new_node_with_optimizer(len); +#ifndef PRODUCT + if (TraceOptimizeFill) { + tty->print_cr("ArrayFill store on backedge, subtract 1 from len."); + } +#endif + } + BasicType t = store->as_Mem()->memory_type(); bool aligned = false; if (offset != NULL && head->init_trip()->is_Con()) { @@ -4049,5 +4062,12 @@ bool PhaseIdealLoop::intrinsify_fill(IdealLoopTree* lpt) { _igvn.replace_node(n, C->top()); } +#ifndef PRODUCT + if (TraceOptimizeFill) { + tty->print("ArrayFill call "); + call->dump(); + } +#endif + return true; } diff --git a/test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFill.jasm b/test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFill.jasm new file mode 100644 index 00000000000..a2bec062e91 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFill.jasm @@ -0,0 +1,178 @@ +/* + * Copyright (c) 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 + * 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. + * + */ + +super public class TestBackedgeLoadArrayFill +{ + public Method "":"()V" + stack 2 locals 1 + { + aload_0; + invokespecial Method java/lang/Object."":"()V"; + return; + } + + static Method test_101:"()V" + stack 20 locals 20 + { + // test_002 in jasm: using try-catch + ldc 6; + istore_0; // i = 6 + ldc 25; + newarray int; + astore_1; // arr = new int[25] + HEAD: + aload_1; + iload_0; + iconst_1; + iastore; // arr[i] = 1 + // second block - the only one -> head block can be copied: one before, one on backedge + try t0; + aload_1; + iload_0; + aload_1; + iload_0; + iaload; + iastore; // arr[i] = arr[i] + goto FINALLY; + endtry t0; + catch t0 java/lang/Exception; + pop; // exception + FINALLY: + iinc 0, 1; // i++ + iload_0; + ldc 21; + if_icmplt HEAD; // if i < 21 + // write array + aload_1; + putstatic Field TestBackedgeLoadArrayFillMain.intA:"[I"; + return; + } + + static Method test_102:"()V" + stack 20 locals 20 + { + // test_002 in jasm: without try-catch + ldc 5; + istore_0; // i = 5 + ldc 25; + newarray int; + astore_1; // arr = new int[25] + HEAD: + aload_1; + iload_0; + iconst_1; + iastore; // arr[i] = 1 + goto SECOND; + // second block - the only one -> head block can be copied: one before, one on backedge + // must have some material before inc, else it is partial peeled away + // And if we set -XX:-PartialPeelLoop, then the counted loop is never detected + SECOND: + aload_1; + iload_0; + aload_1; + iload_0; + iaload; + iastore; // arr[i] = arr[i] + iinc 0, 1; // i++ + iload_0; + ldc 21; + if_icmplt HEAD; // if i < 21 + // write array + aload_1; + putstatic Field TestBackedgeLoadArrayFillMain.intA:"[I"; + return; + } + + static Method test_103:"()V" + stack 20 locals 20 + { + // test_002 in jasm: without try-catch, and second array + ldc 7; + istore_0; // i = 7 + ldc 25; + newarray int; + astore_1; // arr = new int[25] + ldc 25; + newarray int; + astore_2; // arr2 = new int[25] + HEAD: + aload_1; + iload_0; + iconst_1; + iastore; // arr[i] = 1 + goto SECOND; + // second block - the only one -> head block can be copied: one before, one on backedge + SECOND: + // we can also do the identity read-write on another array - it just has to eventually disappear + aload_2; + iload_0; + aload_2; + iload_0; + iaload; + iastore; // arr2[i] = arr2[i] + + iinc 0, 1; // i++ + iload_0; + ldc 21; + if_icmplt HEAD; // if i < 21 + // write array + aload_1; + putstatic Field TestBackedgeLoadArrayFillMain.intA:"[I"; + return; + } + + static Method test_104:"()V" + stack 20 locals 20 + { + ldc 9; + istore_0; // i = 9 + ldc 25; + newarray int; + astore_1; // arr = new int[25] + HEAD: + aload_1; + iload_0; + iconst_1; + iastore; // arr[i] = 1 + goto SECOND; + // second block - the only one -> head block can be copied: one before, one on backedge + SECOND: + // CFG leads to partial peel -> load moved into loop body, then intrinsified + iload_0; + ldc 2; + irem; + ifeq SKIP; + + SKIP: + + iinc 0, 1; // i++ + iload_0; + ldc 21; + if_icmplt HEAD; // if i < 21 + // write array + aload_1; + putstatic Field TestBackedgeLoadArrayFillMain.intA:"[I"; + return; + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFillMain.java b/test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFillMain.java new file mode 100644 index 00000000000..878c04ecd83 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestBackedgeLoadArrayFillMain.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 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 + * 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. + * + */ + +/* + * @test + * @bug 8299179 + * @summary ArrayFill: if store is on backedge, last iteration is not to be executed. + * @library /test/lib + * @compile TestBackedgeLoadArrayFill.jasm + * @run main/othervm + * -XX:CompileCommand=compileonly,TestBackedgeLoadArrayFill*::test* + * -XX:-TieredCompilation -Xcomp -XX:+OptimizeFill + * TestBackedgeLoadArrayFillMain + * @run main/othervm + * -XX:CompileCommand=compileonly,TestBackedgeLoadArrayFill*::test* + * -XX:-TieredCompilation -Xcomp -XX:+OptimizeFill + * -XX:LoopUnrollLimit=1 + * TestBackedgeLoadArrayFillMain + */ + +import jdk.test.lib.Asserts; + +public class TestBackedgeLoadArrayFillMain { + static long[] longA; + static int[] intA; + static short[] shortA; + static byte[] byteA; + + static class Data { + long longValue; + int intValue; + short shortValue; + byte byteValue; + + Data(int value) { + longValue = (long) value; + intValue = (int) value; + shortValue = (short) value; + longValue = (byte) value; + } + } + + public static long longSum() { + long s = 0; + for (long v : longA) { s += v; } + return s; + } + + public static int intSum() { + int s = 0; + for (int v : intA) { s += v; } + return s; + } + + public static short shortSum() { + short s = 0; + for (short v : shortA) { s += v; } + return s; + } + + public static byte byteSum() { + byte s = 0; + for (byte v : byteA) { s += v; } + return s; + } + + static void test_001() { + // long seems not yet supported + int i = 6; + long arr[] = new long[22]; + do { + arr[i] = 1; + try { + arr[i] = arr[i]; + } catch (Exception e) { + } + } while (++i < 20); + longA = arr; + } + + static void test_002() { + // jint_fill + int i = 6; + int arr[] = new int[22]; + do { + arr[i] = 1; + try { + arr[i] = arr[i]; + } catch (Exception e) { + } + } while (++i < 20); + intA = arr; + } + + static void test_003() { + // jshort_fill + int i = 6; + short arr[] = new short[22]; + do { + // first block of loop: copied before loop, and onto backedge -> store on backedge + arr[i] = 1; + // second block of loop + try { + arr[i] = arr[i]; + } catch (Exception e) { + } + } while (++i < 20); + shortA = arr; + } + + static void test_004() { + // jbyte_fill + int i = 6; + byte arr[] = new byte[22]; + do { + arr[i] = 1; + try { + arr[i] = arr[i]; + } catch (Exception e) { + } + } while (++i < 20); + byteA = arr; + } + + static void test_005() { + // Note: currently unrolled, not intrinsified (unless -XX:LoopUnrollLimit=1) + int arr[] = new int[22]; + for (int i = 6; i < 20; i++) { + arr[i] = 1; + } + intA = arr; + } + + static void test_006() { + // Note: currently unrolled, not intrinsified (unless -XX:LoopUnrollLimit=1) + // Load in normal body, because not moved to backedge during parsing. + int i = 6; + int arr[] = new int[22]; + do { + arr[i] = 1; + } while (++i < 20); + intA = arr; + } + + static void test_007() { + int i = 6; + int arr[] = new int[22]; + do { + // still not on backedge [7,20) partial peel + arr[i] = 1; + try { int x = arr[i]; } catch (Exception e) {} + } while (++i < 20); + intA = arr; + } + + static void test_008(Data data) { + // Because of conditional in loop, at first not intrinsified, and also not unrolled. + // After unswitching both loops are intrinsified. + // I stole this idea from TestOptimizeFillWithStripMinedLoop.java + int i = 6; + int arr[] = new int[22]; + do { + arr[i] = (data == null) ? 1 : data.intValue; + } while (++i < 20); + intA = arr; + } + + static void test_009() { + // Cast to int leads to "missing use of index", not intrinsified + int arr[] = new int[22]; + for (long i = 6; i < 20; i++) { + arr[(int)i] = 1; + } + intA = arr; + } + + + public static void main(String[] strArr) { + test_001(); + Asserts.assertEQ(longSum(), (long)14); + test_002(); + Asserts.assertEQ(intSum(), 14); + test_003(); + Asserts.assertEQ(shortSum(), (short)14); + test_004(); + Asserts.assertEQ(byteSum(), (byte)14); + test_005(); + Asserts.assertEQ(intSum(), 14); + test_006(); + Asserts.assertEQ(intSum(), 14); + test_007(); + Asserts.assertEQ(intSum(), 14); + test_008(new Data(1)); + Asserts.assertEQ(intSum(), 14); + test_008(null); + Asserts.assertEQ(intSum(), 14); + test_009(); + Asserts.assertEQ(intSum(), 14); + TestBackedgeLoadArrayFill t = new TestBackedgeLoadArrayFill(); + t.test_101(); + Asserts.assertEQ(intSum(), 15); + t.test_102(); + Asserts.assertEQ(intSum(), 16); + t.test_103(); + Asserts.assertEQ(intSum(), 14); + t.test_104(); + Asserts.assertEQ(intSum(), 12); + } +} + From 4cfe4d7b6f4520f9f486551c5568e388e7ba2d9f Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:22:47 +0000 Subject: [PATCH 064/217] 8300823: UB: Compile::_phase_optimize_finished is initialized too late Backport-of: e4252bb91478e9c2f0a5bbdae7cd663838d91b1b --- src/hotspot/share/opto/compile.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 201a1b2344d..fddae5d0e13 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -953,6 +953,12 @@ void Compile::Init(int aliaslevel) { _immutable_memory = NULL; // filled in at first inquiry +#ifdef ASSERT + _type_verify_symmetry = true; + _phase_optimize_finished = false; + _exception_backedge = false; +#endif + // Globally visible Nodes // First set TOP to NULL to give safe behavior during creation of RootNode set_cached_top_node(NULL); @@ -1055,12 +1061,6 @@ void Compile::Init(int aliaslevel) { Copy::zero_to_bytes(_alias_cache, sizeof(_alias_cache)); // A NULL adr_type hits in the cache right away. Preload the right answer. probe_alias_cache(NULL)->_index = AliasIdxTop; - -#ifdef ASSERT - _type_verify_symmetry = true; - _phase_optimize_finished = false; - _exception_backedge = false; -#endif } //---------------------------init_start---------------------------------------- From 0ca8d00f6de490560bd86d2e9fbe1098cd1522e7 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:23:39 +0000 Subject: [PATCH 065/217] 8297730: C2: Arraycopy intrinsic throws incorrect exception Backport-of: 5a478ef7759e64da6d17426673700ff0d9c66b33 --- src/hotspot/share/opto/library_call.cpp | 171 +++++++--- src/hotspot/share/opto/library_call.hpp | 7 +- .../TestArrayCopyIntrinsicWithUCT.java | 312 ++++++++++++++++++ 3 files changed, 434 insertions(+), 56 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyIntrinsicWithUCT.java diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index b5970545c4e..e8af4c123c7 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -4395,24 +4395,7 @@ JVMState* LibraryCallKit::arraycopy_restore_alloc_state(AllocateArrayNode* alloc } if (no_interfering_store) { - JVMState* old_jvms = alloc->jvms()->clone_shallow(C); - uint size = alloc->req(); - SafePointNode* sfpt = new SafePointNode(size, old_jvms); - old_jvms->set_map(sfpt); - for (uint i = 0; i < size; i++) { - sfpt->init_req(i, alloc->in(i)); - } - // re-push array length for deoptimization - sfpt->ins_req(old_jvms->stkoff() + old_jvms->sp(), alloc->in(AllocateNode::ALength)); - old_jvms->set_sp(old_jvms->sp()+1); - old_jvms->set_monoff(old_jvms->monoff()+1); - old_jvms->set_scloff(old_jvms->scloff()+1); - old_jvms->set_endoff(old_jvms->endoff()+1); - old_jvms->set_should_reexecute(true); - - sfpt->set_i_o(map()->i_o()); - sfpt->set_memory(map()->memory()); - sfpt->set_control(map()->control()); + SafePointNode* sfpt = create_safepoint_with_state_before_array_allocation(alloc); JVMState* saved_jvms = jvms(); saved_reexecute_sp = _reexecute_sp; @@ -4427,6 +4410,30 @@ JVMState* LibraryCallKit::arraycopy_restore_alloc_state(AllocateArrayNode* alloc return NULL; } +// Clone the JVMState of the array allocation and create a new safepoint with it. Re-push the array length to the stack +// such that uncommon traps can be emitted to re-execute the array allocation in the interpreter. +SafePointNode* LibraryCallKit::create_safepoint_with_state_before_array_allocation(const AllocateArrayNode* alloc) const { + JVMState* old_jvms = alloc->jvms()->clone_shallow(C); + uint size = alloc->req(); + SafePointNode* sfpt = new SafePointNode(size, old_jvms); + old_jvms->set_map(sfpt); + for (uint i = 0; i < size; i++) { + sfpt->init_req(i, alloc->in(i)); + } + // re-push array length for deoptimization + sfpt->ins_req(old_jvms->stkoff() + old_jvms->sp(), alloc->in(AllocateNode::ALength)); + old_jvms->set_sp(old_jvms->sp()+1); + old_jvms->set_monoff(old_jvms->monoff()+1); + old_jvms->set_scloff(old_jvms->scloff()+1); + old_jvms->set_endoff(old_jvms->endoff()+1); + old_jvms->set_should_reexecute(true); + + sfpt->set_i_o(map()->i_o()); + sfpt->set_memory(map()->memory()); + sfpt->set_control(map()->control()); + return sfpt; +} + // In case of a deoptimization, we restart execution at the // allocation, allocating a new array. We would leave an uninitialized // array in the heap that GCs wouldn't expect. Move the allocation @@ -4434,18 +4441,20 @@ JVMState* LibraryCallKit::arraycopy_restore_alloc_state(AllocateArrayNode* alloc // deoptimize. This is possible because tightly_coupled_allocation() // guarantees there's no observer of the allocated array at this point // and the control flow is simple enough. -void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, +void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms_before_guards, int saved_reexecute_sp, uint new_idx) { - if (saved_jvms != NULL && !stopped()) { + if (saved_jvms_before_guards != NULL && !stopped()) { + replace_unrelated_uncommon_traps_with_alloc_state(alloc, saved_jvms_before_guards); + assert(alloc != NULL, "only with a tightly coupled allocation"); // restore JVM state to the state at the arraycopy - saved_jvms->map()->set_control(map()->control()); - assert(saved_jvms->map()->memory() == map()->memory(), "memory state changed?"); - assert(saved_jvms->map()->i_o() == map()->i_o(), "IO state changed?"); + saved_jvms_before_guards->map()->set_control(map()->control()); + assert(saved_jvms_before_guards->map()->memory() == map()->memory(), "memory state changed?"); + assert(saved_jvms_before_guards->map()->i_o() == map()->i_o(), "IO state changed?"); // If we've improved the types of some nodes (null check) while // emitting the guards, propagate them to the current state - map()->replaced_nodes().apply(saved_jvms->map(), new_idx); - set_jvms(saved_jvms); + map()->replaced_nodes().apply(saved_jvms_before_guards->map(), new_idx); + set_jvms(saved_jvms_before_guards); _reexecute_sp = saved_reexecute_sp; // Remove the allocation from above the guards @@ -4521,6 +4530,58 @@ void LibraryCallKit::arraycopy_move_allocation_here(AllocateArrayNode* alloc, No } } +// Unrelated UCTs between the array allocation and the array copy, which are considered safe by tightly_coupled_allocation(), +// need to be replaced by an UCT with a state before the array allocation (including the array length). This is necessary +// because we could hit one of these UCTs (which are executed before the emitted array copy guards and the actual array +// allocation which is moved down in arraycopy_move_allocation_here()). When later resuming execution in the interpreter, +// we would have wrongly skipped the array allocation. To prevent this, we resume execution at the array allocation in +// the interpreter similar to what we are doing for the newly emitted guards for the array copy. +void LibraryCallKit::replace_unrelated_uncommon_traps_with_alloc_state(AllocateArrayNode* alloc, + JVMState* saved_jvms_before_guards) { + if (saved_jvms_before_guards->map()->control()->is_IfProj()) { + // There is at least one unrelated uncommon trap which needs to be replaced. + SafePointNode* sfpt = create_safepoint_with_state_before_array_allocation(alloc); + + JVMState* saved_jvms = jvms(); + const int saved_reexecute_sp = _reexecute_sp; + set_jvms(sfpt->jvms()); + _reexecute_sp = jvms()->sp(); + + replace_unrelated_uncommon_traps_with_alloc_state(saved_jvms_before_guards); + + // Restore state + set_jvms(saved_jvms); + _reexecute_sp = saved_reexecute_sp; + } +} + +// Replace the unrelated uncommon traps with new uncommon trap nodes by reusing the action and reason. The new uncommon +// traps will have the state of the array allocation. Let the old uncommon trap nodes die. +void LibraryCallKit::replace_unrelated_uncommon_traps_with_alloc_state(JVMState* saved_jvms_before_guards) { + Node* if_proj = saved_jvms_before_guards->map()->control(); // Start the search right before the newly emitted guards + while (if_proj->is_IfProj()) { + CallStaticJavaNode* uncommon_trap = get_uncommon_trap_from_success_proj(if_proj); + if (uncommon_trap != nullptr) { + create_new_uncommon_trap(uncommon_trap); + } + assert(if_proj->in(0)->is_If(), "must be If"); + if_proj = if_proj->in(0)->in(0); + } + assert(if_proj->is_Proj() && if_proj->in(0)->is_Initialize(), + "must have reached control projection of init node"); +} + +void LibraryCallKit::create_new_uncommon_trap(CallStaticJavaNode* uncommon_trap_call) { + const int trap_request = uncommon_trap_call->uncommon_trap_request(); + assert(trap_request != 0, "no valid UCT trap request"); + PreserveJVMState pjvms(this); + set_control(uncommon_trap_call->in(0)); + uncommon_trap(Deoptimization::trap_request_reason(trap_request), + Deoptimization::trap_request_action(trap_request)); + assert(stopped(), "Should be stopped"); + _gvn.hash_delete(uncommon_trap_call); + uncommon_trap_call->set_req(0, top()); // not used anymore, kill it +} //------------------------------inline_arraycopy----------------------- // public static native void java.lang.System.arraycopy(Object src, int srcPos, @@ -4541,12 +4602,12 @@ bool LibraryCallKit::inline_arraycopy() { AllocateArrayNode* alloc = tightly_coupled_allocation(dest); int saved_reexecute_sp = -1; - JVMState* saved_jvms = arraycopy_restore_alloc_state(alloc, saved_reexecute_sp); + JVMState* saved_jvms_before_guards = arraycopy_restore_alloc_state(alloc, saved_reexecute_sp); // See arraycopy_restore_alloc_state() comment // if alloc == NULL we don't have to worry about a tightly coupled allocation so we can emit all needed guards - // if saved_jvms != NULL (then alloc != NULL) then we can handle guards and a tightly coupled allocation - // if saved_jvms == NULL and alloc != NULL, we can't emit any guards - bool can_emit_guards = (alloc == NULL || saved_jvms != NULL); + // if saved_jvms_before_guards != NULL (then alloc != NULL) then we can handle guards and a tightly coupled allocation + // if saved_jvms_before_guards == NULL and alloc != NULL, we can't emit any guards + bool can_emit_guards = (alloc == NULL || saved_jvms_before_guards != NULL); // The following tests must be performed // (1) src and dest are arrays. @@ -4562,12 +4623,12 @@ bool LibraryCallKit::inline_arraycopy() { // (3) src and dest must not be null. // always do this here because we need the JVM state for uncommon traps Node* null_ctl = top(); - src = saved_jvms != NULL ? null_check_oop(src, &null_ctl, true, true) : null_check(src, T_ARRAY); + src = saved_jvms_before_guards != NULL ? null_check_oop(src, &null_ctl, true, true) : null_check(src, T_ARRAY); assert(null_ctl->is_top(), "no null control here"); dest = null_check(dest, T_ARRAY); if (!can_emit_guards) { - // if saved_jvms == NULL and alloc != NULL, we don't emit any + // if saved_jvms_before_guards == NULL and alloc != NULL, we don't emit any // guards but the arraycopy node could still take advantage of a // tightly allocated allocation. tightly_coupled_allocation() is // called again to make sure it takes the null check above into @@ -4681,7 +4742,7 @@ bool LibraryCallKit::inline_arraycopy() { ciMethod* trap_method = method(); int trap_bci = bci(); - if (saved_jvms != NULL) { + if (saved_jvms_before_guards != NULL) { trap_method = alloc->jvms()->method(); trap_bci = alloc->jvms()->bci(); } @@ -4753,10 +4814,9 @@ bool LibraryCallKit::inline_arraycopy() { const TypeKlassPtr* dest_klass_t = _gvn.type(dest_klass)->is_klassptr(); const Type *toop = TypeOopPtr::make_from_klass(dest_klass_t->klass()); src = _gvn.transform(new CheckCastPPNode(control(), src, toop)); + arraycopy_move_allocation_here(alloc, dest, saved_jvms_before_guards, saved_reexecute_sp, new_idx); } - arraycopy_move_allocation_here(alloc, dest, saved_jvms, saved_reexecute_sp, new_idx); - if (stopped()) { return true; } @@ -4821,28 +4881,15 @@ LibraryCallKit::tightly_coupled_allocation(Node* ptr) { // There may be guards which feed into the slow_region. // Any other control flow means that we might not get a chance // to finish initializing the allocated object. - if ((ctl->is_IfFalse() || ctl->is_IfTrue()) && ctl->in(0)->is_If()) { - IfNode* iff = ctl->in(0)->as_If(); - Node* not_ctl = iff->proj_out_or_null(1 - ctl->as_Proj()->_con); - assert(not_ctl != NULL && not_ctl != ctl, "found alternate"); - // One more try: Various low-level checks bottom out in - // uncommon traps. If the debug-info of the trap omits - // any reference to the allocation, as we've already - // observed, then there can be no objection to the trap. - bool found_trap = false; - for (DUIterator_Fast jmax, j = not_ctl->fast_outs(jmax); j < jmax; j++) { - Node* obs = not_ctl->fast_out(j); - if (obs->in(0) == not_ctl && obs->is_Call() && - (obs->as_Call()->entry_point() == SharedRuntime::uncommon_trap_blob()->entry_point())) { - found_trap = true; break; - } - } - if (found_trap) { - ctl = iff->in(0); // This test feeds a harmless uncommon trap. - continue; - } + // Various low-level checks bottom out in uncommon traps. These + // are considered safe since we've already checked above that + // there is no unexpected observer of this allocation. + if (get_uncommon_trap_from_success_proj(ctl) != nullptr) { + assert(ctl->in(0)->is_If(), "must be If"); + ctl = ctl->in(0)->in(0); + } else { + return nullptr; } - return NULL; } // If we get this far, we have an allocation which immediately @@ -4853,6 +4900,20 @@ LibraryCallKit::tightly_coupled_allocation(Node* ptr) { return alloc; } +CallStaticJavaNode* LibraryCallKit::get_uncommon_trap_from_success_proj(Node* node) { + if (node->is_IfProj()) { + Node* other_proj = node->as_IfProj()->other_if_proj(); + for (DUIterator_Fast jmax, j = other_proj->fast_outs(jmax); j < jmax; j++) { + Node* obs = other_proj->fast_out(j); + if (obs->in(0) == other_proj && obs->is_CallStaticJava() && + (obs->as_CallStaticJava()->entry_point() == SharedRuntime::uncommon_trap_blob()->entry_point())) { + return obs->as_CallStaticJava(); + } + } + } + return nullptr; +} + //-------------inline_encodeISOArray----------------------------------- // encode char[] to byte[] in ISO_8859_1 or ASCII bool LibraryCallKit::inline_encodeISOArray(bool ascii) { diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 15e2de48bec..9b46475fb2f 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -253,8 +253,13 @@ class LibraryCallKit : public GraphKit { // Helper functions for inlining arraycopy bool inline_arraycopy(); AllocateArrayNode* tightly_coupled_allocation(Node* ptr); + static CallStaticJavaNode* get_uncommon_trap_from_success_proj(Node* node); + SafePointNode* create_safepoint_with_state_before_array_allocation(const AllocateArrayNode* alloc) const; + void replace_unrelated_uncommon_traps_with_alloc_state(AllocateArrayNode* alloc, JVMState* saved_jvms_before_guards); + void replace_unrelated_uncommon_traps_with_alloc_state(JVMState* saved_jvms_before_guards); + void create_new_uncommon_trap(CallStaticJavaNode* uncommon_trap_call); JVMState* arraycopy_restore_alloc_state(AllocateArrayNode* alloc, int& saved_reexecute_sp); - void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms, int saved_reexecute_sp, + void arraycopy_move_allocation_here(AllocateArrayNode* alloc, Node* dest, JVMState* saved_jvms_before_guards, int saved_reexecute_sp, uint new_idx); typedef enum { LS_get_add, LS_get_set, LS_cmp_swap, LS_cmp_swap_weak, LS_cmp_exchange } LoadStoreKind; diff --git a/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyIntrinsicWithUCT.java b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyIntrinsicWithUCT.java new file mode 100644 index 00000000000..1ce5e19cbf2 --- /dev/null +++ b/test/hotspot/jtreg/compiler/arraycopy/TestArrayCopyIntrinsicWithUCT.java @@ -0,0 +1,312 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * @test + * @bug 8297730 + * @summary Test taking UCT between array allocation and array copy to report correct exception. + * @library /test/lib + * @run main/othervm -Xcomp -XX:-TieredCompilation + * -XX:CompileCommand=compileonly,compiler.arraycopy.TestArrayCopyIntrinsicWithUCT::test* + * compiler.arraycopy.TestArrayCopyIntrinsicWithUCT + */ + +package compiler.arraycopy; + +import jdk.test.lib.Asserts; + +import java.util.function.Function; +import java.util.function.Supplier; + +public class TestArrayCopyIntrinsicWithUCT { + static int zero = 0; + static int zero2 = 0; + static int minusOne = -1; + static int iFld; + static int iFld2; + static boolean flag; + static byte[] byArrNull = null; + static A aFld = null; + + static public void main(String[] args) { + System.out.println("Start"); // Ensure loaded. + new A(); // Ensure loaded + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSize); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSize2); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeFldSize); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeFldSize2); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeStore); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeStore2); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZero); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZero2); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZero3); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZero4); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZero5); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZero6); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZero7); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZeroFld); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZeroFld2); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZeroFld3); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZeroFld4); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZeroFld5); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZeroFld6); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZeroFld7); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeDivZeroNullPointer); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeSizeComplex); + runNegativeSize(TestArrayCopyIntrinsicWithUCT::testNegativeControlFlowNotAllowed); + flag = false; + runNegativeSizeHalf(); + runNegativeSizeHalf(); + } + + static void runNegativeSize(Supplier testMethod) { + try { + testMethod.get(); + Asserts.fail("should throw exception"); + } catch (NegativeArraySizeException e) { + // Expected + } + } + + static void runNegativeSize(Function testMethod) { + try { + testMethod.apply(null); + Asserts.fail("should throw exception"); + } catch (NegativeArraySizeException e) { + // Expected + } + } + + static byte[] testNegativeSize(byte[] byArr) { + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = byArr.length; // null check trap would fail + System.arraycopy(byArr, 0, b, 0, len); + return b; + } + + static byte[] testNegativeSize2() { + byte[] byArr = new byte[8]; + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = byArrNull.length; // null check trap would fail + System.arraycopy(byArr, 0, b, 0, len); + return b; + } + + static byte[] testNegativeFldSize(byte[] byArr) { + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + int len = byArr.length; // null check trap would fail + System.arraycopy(byArr, 0, b, 0, len); + return b; + } + static byte[] testNegativeFldSize2() { + byte[] byArr = new byte[8]; + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + int len = byArrNull.length; // null check trap would fail + System.arraycopy(byArr, 0, b, 0, len); + return b; + } + + static byte[] testNegativeSizeStore(byte[] byArr) { + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + iFld++; // Since we have a store here, we do not move the allocation down + int len = byArr.length; // null check trap would fail + System.arraycopy(byArr, 0, b, 0, len); + return b; + } + + static byte[] testNegativeSizeStore2() { + byte[] byArr = new byte[8]; + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + iFld++; // Since we have a store here, we do not move the allocation down + int len = byArrNull.length; // null check trap would fail + System.arraycopy(byArr, 0, b, 0, len); + return b; + } + + static byte[] testNegativeSizeDivZero(byte[] byArr) { + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = 8 / zero; // div by zero trap would fail + System.arraycopy(byArr, 0, b, 0, len); + return b; + } + + static byte[] testNegativeSizeDivZero2() { + byte[] byArr = new byte[8]; + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = 8 / zero; // div by zero trap would fail + System.arraycopy(byArr, 0, b, 0, len); + return b; + } + + static byte[] testNegativeSizeDivZero3(byte[] byArr) { + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = 8 / zero; // div by zero trap would fail + System.arraycopy(byArr, 0, b, 0, iFld2); + iFld = len; + return b; + } + + static byte[] testNegativeSizeDivZero4(byte[] byArr) { + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = 8 / zero / zero2; // 2 div by zero traps would fail + System.arraycopy(byArr, 0, b, 0, iFld2); + iFld = len; + return b; + } + + static byte[] testNegativeSizeDivZero5(byte[] byArr) { + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + int len = 8 / zero / zero2; // 2 div by zero traps would fail + System.arraycopy(byArr, 0, b, 0, iFld2); + iFld = len; + return b; + } + + static byte[] testNegativeSizeDivZero6(byte[] byArr) { + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + int len = 8 / zero / zero2; // 2 div by zero traps would fail + System.arraycopy(byArr, 0, b, 0, 8); + iFld = len; + return b; + } + + static byte[] testNegativeSizeDivZero7(byte[] byArr) { + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = 8 / zero / zero2; // 2 div by zero traps would fail + System.arraycopy(byArr, 0, b, 0, 8); + iFld = len; + return b; + } + + static byte[] testNegativeSizeDivZeroFld(byte[] byArr) { + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = minusOne / zero; // div by zero trap would fail + System.arraycopy(byArr, 0, b, 0, len); + return b; + } + + static byte[] testNegativeSizeDivZeroFld2() { + byte[] byArr = new byte[8]; + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = minusOne / zero; // div by zero trap would fail + System.arraycopy(byArr, 0, b, 0, len); + return b; + } + + static byte[] testNegativeSizeDivZeroFld3(byte[] byArr) { + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = minusOne / zero; // div by zero trap would fail + System.arraycopy(byArr, 0, b, 0, iFld2); + iFld = len; + return b; + } + + static byte[] testNegativeSizeDivZeroFld4(byte[] byArr) { + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = minusOne / zero / zero2; // div by zero trap would fail + System.arraycopy(byArr, 0, b, 0, iFld2); + iFld = len; + return b; + } + + static byte[] testNegativeSizeDivZeroFld5(byte[] byArr) { + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + int len = minusOne / zero / zero2; // div by zero trap would fail + System.arraycopy(byArr, 0, b, 0, iFld2); + iFld = len; + return b; + } + + static byte[] testNegativeSizeDivZeroFld6(byte[] byArr) { + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + int len = minusOne / zero / zero2; // div by zero trap would fail + System.arraycopy(byArr, 0, b, 0, 8); + iFld = len; + return b; + } + + static byte[] testNegativeSizeDivZeroFld7(byte[] byArr) { + byte[] b = new byte[-1]; // throws NegativeArraySizeException + int len = minusOne / zero / zero2; // div by zero trap would fail + System.arraycopy(byArr, 0, b, 0, 8); + iFld = len; + return b; + } + + static byte[] testNegativeSizeDivZeroNullPointer(byte[] byArr) { + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + int x = minusOne / zero / zero2; // div by zero trap would fail + int len = byArr.length; + System.arraycopy(byArr, 0, b, 0, len); + iFld = x; + return b; + } + + static byte[] testNegativeSizeComplex(byte[] byArr) { + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + int x = minusOne / zero; // div by zero trap would fail + int y = aFld.i; + int len = byArr.length; + x = x + aFld.i2 / zero2; + System.arraycopy(byArr, 0, b, 0, x); + iFld = x + y; + return b; + } + + // Optimization not applied because of additional control flow that is not considered safe. + static byte[] testNegativeControlFlowNotAllowed(byte[] byArr) { + int x = 23; + byte[] b = new byte[minusOne]; // throws NegativeArraySizeException + if (flag) { + x = 34; + } + int len = x / zero; + System.arraycopy(byArr, 0, b, 0, 8); + iFld = len; + return b; + } + + static void runNegativeSizeHalf() { + try { + testNegativeSizeHalf(null); + Asserts.fail("should throw exception"); + } catch (NegativeArraySizeException e) { + Asserts.assertTrue(flag, "wrongly caught NegativeArraySizeException"); + } catch (NullPointerException e) { + Asserts.assertFalse(flag, "wrongly caught NullPointerException"); + } + flag = !flag; + } + + static byte[] testNegativeSizeHalf(byte[] byArr) { + int size = flag ? -1 : 1; + byte[] b = new byte[size]; // throws NegativeArraySizeException if size == -1 + int len = byArr.length; // throws NullPointerException if size == 1 + System.arraycopy(byArr, 0, b, 0, len); + return b; + } +} + +class A { + int i, i2; +} From 36c1c0a76a2d3a1b49b888d6416cf522dd854867 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:26:00 +0000 Subject: [PATCH 066/217] 8301123: Enable Symbol refcounting underflow checks in PRODUCT Backport-of: fccf818972f15bc4f69ce9566b5cd4b7e7777107 --- src/hotspot/share/oops/symbol.cpp | 6 ------ test/hotspot/gtest/classfile/test_symbolTable.cpp | 9 ++++++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp index 3884c79f290..581a5f8f6dd 100644 --- a/src/hotspot/share/oops/symbol.cpp +++ b/src/hotspot/share/oops/symbol.cpp @@ -310,10 +310,8 @@ bool Symbol::try_increment_refcount() { // this caller. void Symbol::increment_refcount() { if (!try_increment_refcount()) { -#ifdef ASSERT print(); fatal("refcount has gone to zero"); -#endif } #ifndef PRODUCT if (refcount() != PERM_REFCOUNT) { // not a permanent symbol @@ -333,10 +331,8 @@ void Symbol::decrement_refcount() { if (refc == PERM_REFCOUNT) { return; // refcount is permanent, permanent is sticky } else if (refc == 0) { -#ifdef ASSERT print(); fatal("refcount underflow"); -#endif return; } else { found = Atomic::cmpxchg(&_hash_and_refcount, old_value, old_value - 1); @@ -356,10 +352,8 @@ void Symbol::make_permanent() { if (refc == PERM_REFCOUNT) { return; // refcount is permanent, permanent is sticky } else if (refc == 0) { -#ifdef ASSERT print(); fatal("refcount underflow"); -#endif return; } else { int hash = extract_hash(old_value); diff --git a/test/hotspot/gtest/classfile/test_symbolTable.cpp b/test/hotspot/gtest/classfile/test_symbolTable.cpp index e2575d5cd23..0f598447441 100644 --- a/test/hotspot/gtest/classfile/test_symbolTable.cpp +++ b/test/hotspot/gtest/classfile/test_symbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -145,3 +145,10 @@ class DriverSymbolThread : public JavaTestThread { TEST_VM(SymbolTable, test_symbol_refcount_parallel) { mt_test_doer(); } + +TEST_VM_FATAL_ERROR_MSG(SymbolTable, test_symbol_underflow, ".*refcount has gone to zero.*") { + Symbol* my_symbol = SymbolTable::new_symbol("my_symbol2023"); + EXPECT_TRUE(my_symbol->refcount() == 1) << "Symbol refcount just created is 1"; + my_symbol->decrement_refcount(); + my_symbol->increment_refcount(); // Should crash even in PRODUCT mode +} From 14e3103d804cc1c7ff6ebd3db8c69163842b2399 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:27:57 +0000 Subject: [PATCH 067/217] 8178806: Better exception logging in crypto code Backport-of: b814cfc39d2a49951e8e1839cb2f42d9b7cf705d --- .../share/classes/javax/crypto/JceSecurity.java.template | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/java.base/share/classes/javax/crypto/JceSecurity.java.template b/src/java.base/share/classes/javax/crypto/JceSecurity.java.template index 69ca07dbc6d..7a344e8e306 100644 --- a/src/java.base/share/classes/javax/crypto/JceSecurity.java.template +++ b/src/java.base/share/classes/javax/crypto/JceSecurity.java.template @@ -235,7 +235,11 @@ final class JceSecurity { // return whether this provider is properly signed and can be used by JCE static boolean canUseProvider(Provider p) { - return getVerificationResult(p) == null; + Exception e = getVerificationResult(p); + if (debug != null && e != null) { + debug.println("Provider verification result: " + e); + } + return e == null; } // dummy object to represent null From 17f5448c19d19803b88edf3a9e61454f67e98cef Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:29:56 +0000 Subject: [PATCH 068/217] 8302151: BMPImageReader throws an exception reading BMP images Backport-of: aa10f0d3ee5d77d83950c9ed4aab11589b822ff4 --- .../imageio/plugins/bmp/BMPImageReader.java | 6 +- .../bmp/BMP1bppImageWithPaletteTest.java | 64 +++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 test/jdk/javax/imageio/plugins/bmp/BMP1bppImageWithPaletteTest.java diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java index 4eeb8b06d9b..8e9b08af725 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/bmp/BMPImageReader.java @@ -615,8 +615,10 @@ else if (size == 124) height = Math.abs(height); } - if (metadata.compression == BI_RGB) { - long imageDataSize = ((long)width * height * (bitsPerPixel / 8)); + if (metadata.compression == BI_RGB && + metadata.paletteSize == 0 && + metadata.bitsPerPixel >= 16) { + long imageDataSize = (((long)width * height * bitsPerPixel) / 8); if (imageDataSize > (bitmapFileSize - bitmapOffset)) { throw new IIOException(I18N.getString("BMPImageReader9")); } diff --git a/test/jdk/javax/imageio/plugins/bmp/BMP1bppImageWithPaletteTest.java b/test/jdk/javax/imageio/plugins/bmp/BMP1bppImageWithPaletteTest.java new file mode 100644 index 00000000000..059127d0da5 --- /dev/null +++ b/test/jdk/javax/imageio/plugins/bmp/BMP1bppImageWithPaletteTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 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 + * 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. + */ + +/* + * @test + * @bug 8302151 + * @summary Tests that we should not try to calculate bitmap image + size using bitmap file size when we have a color palette + */ + +import java.io.ByteArrayInputStream; +import java.io.EOFException; +import java.io.IOException; +import javax.imageio.ImageIO; + +public class BMP1bppImageWithPaletteTest { + + public static void main(String[] args) throws IOException { + // incomplete 1bpp BMP byte stream with color palette and + // invalid file size data + byte[] corruptedBmp = { (byte) 0x42, (byte) 0x4d, (byte) 0x0e, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x3e, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x28, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xa2, (byte) 0x06, (byte) 0x00, (byte) 0x00, (byte) 0xb4, + (byte) 0x08, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, + (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0xe0, (byte) 0x57, (byte) 0x07, (byte) 0x00, + (byte) 0xc2, (byte) 0x1e, (byte) 0x00, (byte) 0x00, (byte) 0xc2, + (byte) 0x1e, (byte) 0x00, (byte) 0x00, (byte) 0x02, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, + (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff + }; + + // We expect EOFException to be thrown + try { + ImageIO.read(new ByteArrayInputStream(corruptedBmp)); + } catch(Exception ex) { + if (!(ex instanceof EOFException)) + throw ex; + } + } +} From ba457ab361c7fde9d10e4da130454cf492502233 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:32:18 +0000 Subject: [PATCH 069/217] 8303588: [JVMCI] make JVMCI source directories conform with standard layout Reviewed-by: mdoerr Backport-of: 9fdbf3cfc4bf58daa93807b47e403536e4681e90 --- make/modules/jdk.internal.vm.ci/Java.gmk | 8 -------- .../src => }/jdk/vm/ci/aarch64/AArch64.java | 0 .../src => }/jdk/vm/ci/aarch64/AArch64Kind.java | 0 .../src => }/jdk/vm/ci/aarch64/package-info.java | 0 .../{jdk.vm.ci.amd64/src => }/jdk/vm/ci/amd64/AMD64.java | 0 .../src => }/jdk/vm/ci/amd64/AMD64Kind.java | 0 .../src => }/jdk/vm/ci/amd64/package-info.java | 0 .../src => }/jdk/vm/ci/code/Architecture.java | 0 .../src => }/jdk/vm/ci/code/BailoutException.java | 0 .../src => }/jdk/vm/ci/code/BytecodeFrame.java | 0 .../src => }/jdk/vm/ci/code/BytecodePosition.java | 0 .../src => }/jdk/vm/ci/code/CPUFeatureName.java | 0 .../src => }/jdk/vm/ci/code/CallingConvention.java | 0 .../src => }/jdk/vm/ci/code/CodeCacheProvider.java | 0 .../{jdk.vm.ci.code/src => }/jdk/vm/ci/code/CodeUtil.java | 0 .../src => }/jdk/vm/ci/code/CompilationRequest.java | 0 .../src => }/jdk/vm/ci/code/CompilationRequestResult.java | 0 .../src => }/jdk/vm/ci/code/CompiledCode.java | 0 .../src => }/jdk/vm/ci/code/DebugInfo.java | 0 .../src => }/jdk/vm/ci/code/InstalledCode.java | 0 .../jdk/vm/ci/code/InvalidInstalledCodeException.java | 0 .../{jdk.vm.ci.code/src => }/jdk/vm/ci/code/Location.java | 0 .../src => }/jdk/vm/ci/code/MemoryBarriers.java | 0 .../src => }/jdk/vm/ci/code/ReferenceMap.java | 0 .../{jdk.vm.ci.code/src => }/jdk/vm/ci/code/Register.java | 0 .../src => }/jdk/vm/ci/code/RegisterArray.java | 0 .../src => }/jdk/vm/ci/code/RegisterAttributes.java | 0 .../src => }/jdk/vm/ci/code/RegisterConfig.java | 0 .../src => }/jdk/vm/ci/code/RegisterSaveLayout.java | 0 .../src => }/jdk/vm/ci/code/RegisterValue.java | 0 .../src => }/jdk/vm/ci/code/StackLockValue.java | 0 .../src => }/jdk/vm/ci/code/StackSlot.java | 0 .../src => }/jdk/vm/ci/code/SuppressFBWarnings.java | 0 .../src => }/jdk/vm/ci/code/TargetDescription.java | 0 .../src => }/jdk/vm/ci/code/ValueKindFactory.java | 0 .../src => }/jdk/vm/ci/code/ValueUtil.java | 0 .../src => }/jdk/vm/ci/code/VirtualObject.java | 0 .../src => }/jdk/vm/ci/code/package-info.java | 0 .../src => }/jdk/vm/ci/code/site/Call.java | 0 .../src => }/jdk/vm/ci/code/site/ConstantReference.java | 0 .../src => }/jdk/vm/ci/code/site/DataPatch.java | 0 .../jdk/vm/ci/code/site/DataSectionReference.java | 0 .../src => }/jdk/vm/ci/code/site/ExceptionHandler.java | 0 .../jdk/vm/ci/code/site/ImplicitExceptionDispatch.java | 0 .../src => }/jdk/vm/ci/code/site/Infopoint.java | 0 .../src => }/jdk/vm/ci/code/site/InfopointReason.java | 0 .../src => }/jdk/vm/ci/code/site/Mark.java | 0 .../src => }/jdk/vm/ci/code/site/Reference.java | 0 .../src => }/jdk/vm/ci/code/site/Site.java | 0 .../src => }/jdk/vm/ci/code/site/package-info.java | 0 .../src => }/jdk/vm/ci/code/stack/InspectedFrame.java | 0 .../jdk/vm/ci/code/stack/InspectedFrameVisitor.java | 0 .../src => }/jdk/vm/ci/code/stack/StackIntrospection.java | 0 .../src => }/jdk/vm/ci/code/stack/package-info.java | 0 .../src => }/jdk/vm/ci/common/InitTimer.java | 0 .../src => }/jdk/vm/ci/common/JVMCIError.java | 0 .../jdk/vm/ci/common/NativeImageReinitialize.java | 0 .../src => }/jdk/vm/ci/common/SuppressFBWarnings.java | 0 .../src => }/jdk/vm/ci/common/package-info.java | 0 .../src => }/jdk/vm/ci/hotspot/Cleaner.java | 0 .../src => }/jdk/vm/ci/hotspot/CompilerToVM.java | 2 -- .../vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java | 0 .../src => }/jdk/vm/ci/hotspot/EmptyEventProvider.java | 0 .../src => }/jdk/vm/ci/hotspot/EventProvider.java | 0 .../src => }/jdk/vm/ci/hotspot/HandleCleaner.java | 0 .../jdk/vm/ci/hotspot/HotSpotCallingConventionType.java | 0 .../jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java | 0 .../jdk/vm/ci/hotspot/HotSpotCompilationRequest.java | 0 .../vm/ci/hotspot/HotSpotCompilationRequestResult.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotCompiledCode.java | 0 .../jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java | 0 .../jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotConstant.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotConstantPool.java | 0 .../jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java | 0 .../vm/ci/hotspot/HotSpotConstantReflectionProvider.java | 0 .../jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotInstalledCode.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotJDKReflection.java | 0 .../jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java | 0 .../jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java | 0 .../jdk/vm/ci/hotspot/HotSpotJVMCICompilerFactory.java | 0 .../jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java | 0 .../ci/hotspot/HotSpotJVMCIUnsupportedOperationError.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotJavaType.java | 0 .../jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java | 0 .../vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java | 0 .../jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotMetaData.java | 0 .../jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java | 0 .../jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotMethod.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotMethodData.java | 0 .../jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java | 0 .../vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotModifiers.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotNmethod.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotObjectConstant.java | 0 .../jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java | 0 .../jdk/vm/ci/hotspot/HotSpotObjectConstantScope.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotReferenceMap.java | 0 .../jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java | 0 .../jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java | 0 .../jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java | 0 .../jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java | 0 .../jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java | 0 .../jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java | 0 .../jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java | 0 .../jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotRuntimeStub.java | 0 .../jdk/vm/ci/hotspot/HotSpotSentinelConstant.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotSignature.java | 0 .../jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java | 0 .../jdk/vm/ci/hotspot/HotSpotStackFrameReference.java | 0 .../jdk/vm/ci/hotspot/HotSpotStackIntrospection.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotVMConfig.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java | 0 .../src => }/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java | 0 .../jdk/vm/ci/hotspot/HotSpotVMEventListener.java | 0 .../vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java | 0 .../src => }/jdk/vm/ci/hotspot/JFR.java | 0 .../src => }/jdk/vm/ci/hotspot/MetaspaceHandleObject.java | 0 .../src => }/jdk/vm/ci/hotspot/MetaspaceObject.java | 0 .../jdk/vm/ci/hotspot/SharedHotSpotSpeculationLog.java | 0 .../jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java | 0 .../src => }/jdk/vm/ci/hotspot/SuppressFBWarnings.java | 0 .../src => }/jdk/vm/ci/hotspot/TranslatedException.java | 0 .../src => }/jdk/vm/ci/hotspot/UnsafeAccess.java | 0 .../src => }/jdk/vm/ci/hotspot/VMEntryPoint.java | 0 .../src => }/jdk/vm/ci/hotspot/VMField.java | 0 .../src => }/jdk/vm/ci/hotspot/VMFlag.java | 0 .../src => }/jdk/vm/ci/hotspot/VMIntrinsicMethod.java | 0 .../aarch64/AArch64HotSpotJVMCIBackendFactory.java | 0 .../ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java | 0 .../jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java | 2 -- .../src => }/jdk/vm/ci/hotspot/aarch64/package-info.java | 0 .../ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java | 0 .../vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java | 0 .../jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java | 0 .../src => }/jdk/vm/ci/hotspot/amd64/package-info.java | 0 .../src => }/jdk/vm/ci/hotspot/package-info.java | 0 .../src => }/jdk/vm/ci/meta/AbstractJavaProfile.java | 0 .../src => }/jdk/vm/ci/meta/AbstractProfiledItem.java | 0 .../src => }/jdk/vm/ci/meta/AllocatableValue.java | 0 .../src => }/jdk/vm/ci/meta/Assumptions.java | 0 .../{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/Constant.java | 0 .../src => }/jdk/vm/ci/meta/ConstantPool.java | 0 .../jdk/vm/ci/meta/ConstantReflectionProvider.java | 0 .../src => }/jdk/vm/ci/meta/DefaultProfilingInfo.java | 0 .../src => }/jdk/vm/ci/meta/DeoptimizationAction.java | 0 .../src => }/jdk/vm/ci/meta/DeoptimizationReason.java | 0 .../src => }/jdk/vm/ci/meta/EncodedSpeculationReason.java | 0 .../src => }/jdk/vm/ci/meta/ExceptionHandler.java | 0 .../src => }/jdk/vm/ci/meta/InvokeTarget.java | 0 .../src => }/jdk/vm/ci/meta/JavaConstant.java | 0 .../src => }/jdk/vm/ci/meta/JavaField.java | 0 .../{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/JavaKind.java | 0 .../src => }/jdk/vm/ci/meta/JavaMethod.java | 0 .../src => }/jdk/vm/ci/meta/JavaMethodProfile.java | 0 .../{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/JavaType.java | 0 .../src => }/jdk/vm/ci/meta/JavaTypeProfile.java | 0 .../src => }/jdk/vm/ci/meta/JavaValue.java | 0 .../src => }/jdk/vm/ci/meta/LineNumberTable.java | 0 .../{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/Local.java | 0 .../src => }/jdk/vm/ci/meta/LocalVariableTable.java | 0 .../src => }/jdk/vm/ci/meta/MemoryAccessProvider.java | 0 .../src => }/jdk/vm/ci/meta/MetaAccessProvider.java | 0 .../{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/MetaUtil.java | 0 .../jdk/vm/ci/meta/MethodHandleAccessProvider.java | 0 .../src => }/jdk/vm/ci/meta/ModifiersProvider.java | 0 .../src => }/jdk/vm/ci/meta/NullConstant.java | 0 .../src => }/jdk/vm/ci/meta/PlatformKind.java | 0 .../src => }/jdk/vm/ci/meta/PrimitiveConstant.java | 0 .../src => }/jdk/vm/ci/meta/ProfilingInfo.java | 0 .../src => }/jdk/vm/ci/meta/RawConstant.java | 0 .../src => }/jdk/vm/ci/meta/ResolvedJavaField.java | 0 .../src => }/jdk/vm/ci/meta/ResolvedJavaMethod.java | 0 .../src => }/jdk/vm/ci/meta/ResolvedJavaType.java | 0 .../src => }/jdk/vm/ci/meta/SerializableConstant.java | 0 .../src => }/jdk/vm/ci/meta/Signature.java | 0 .../src => }/jdk/vm/ci/meta/SpeculationLog.java | 0 .../src => }/jdk/vm/ci/meta/SuppressFBWarnings.java | 0 .../{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/TriState.java | 0 .../src => }/jdk/vm/ci/meta/UnresolvedJavaField.java | 0 .../src => }/jdk/vm/ci/meta/UnresolvedJavaMethod.java | 0 .../src => }/jdk/vm/ci/meta/UnresolvedJavaType.java | 0 .../src => }/jdk/vm/ci/meta/VMConstant.java | 0 .../{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/Value.java | 0 .../src => }/jdk/vm/ci/meta/ValueKind.java | 0 .../src => }/jdk/vm/ci/meta/package-info.java | 0 .../src => }/jdk/vm/ci/runtime/JVMCI.java | 0 .../src => }/jdk/vm/ci/runtime/JVMCIBackend.java | 0 .../src => }/jdk/vm/ci/runtime/JVMCICompiler.java | 0 .../src => }/jdk/vm/ci/runtime/JVMCICompilerFactory.java | 0 .../src => }/jdk/vm/ci/runtime/JVMCIRuntime.java | 0 .../src => }/jdk/vm/ci/runtime/package-info.java | 0 .../src => }/jdk/vm/ci/services/JVMCIPermission.java | 0 .../src => }/jdk/vm/ci/services/JVMCIServiceLocator.java | 0 .../src => }/jdk/vm/ci/services/Services.java | 0 .../src => }/jdk/vm/ci/services/SuppressFBWarnings.java | 0 .../src => }/jdk/vm/ci/services/VMEntryPoint.java | 0 .../src => }/jdk/vm/ci/services/package-info.java | 0 205 files changed, 12 deletions(-) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.aarch64/src => }/jdk/vm/ci/aarch64/AArch64.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.aarch64/src => }/jdk/vm/ci/aarch64/AArch64Kind.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.aarch64/src => }/jdk/vm/ci/aarch64/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.amd64/src => }/jdk/vm/ci/amd64/AMD64.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.amd64/src => }/jdk/vm/ci/amd64/AMD64Kind.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.amd64/src => }/jdk/vm/ci/amd64/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/Architecture.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/BailoutException.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/BytecodeFrame.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/BytecodePosition.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/CPUFeatureName.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/CallingConvention.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/CodeCacheProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/CodeUtil.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/CompilationRequest.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/CompilationRequestResult.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/CompiledCode.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/DebugInfo.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/InstalledCode.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/InvalidInstalledCodeException.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/Location.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/MemoryBarriers.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/ReferenceMap.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/Register.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/RegisterArray.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/RegisterAttributes.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/RegisterConfig.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/RegisterSaveLayout.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/RegisterValue.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/StackLockValue.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/StackSlot.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/SuppressFBWarnings.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/TargetDescription.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/ValueKindFactory.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/ValueUtil.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/VirtualObject.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/Call.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/ConstantReference.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/DataPatch.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/DataSectionReference.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/ExceptionHandler.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/ImplicitExceptionDispatch.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/Infopoint.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/InfopointReason.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/Mark.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/Reference.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/Site.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/site/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/stack/InspectedFrame.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/stack/InspectedFrameVisitor.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/stack/StackIntrospection.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.code/src => }/jdk/vm/ci/code/stack/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.common/src => }/jdk/vm/ci/common/InitTimer.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.common/src => }/jdk/vm/ci/common/JVMCIError.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.common/src => }/jdk/vm/ci/common/NativeImageReinitialize.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.common/src => }/jdk/vm/ci/common/SuppressFBWarnings.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.common/src => }/jdk/vm/ci/common/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/Cleaner.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/CompilerToVM.java (99%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/EmptyEventProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/EventProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HandleCleaner.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotCompilationRequest.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotCompilationRequestResult.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotCompiledCode.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotConstantPool.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotInstalledCode.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotJDKReflection.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotJVMCICompilerFactory.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotJVMCIUnsupportedOperationError.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotJavaType.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotMetaData.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotMethod.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotMethodData.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotModifiers.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotNmethod.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotObjectConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotObjectConstantScope.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotReferenceMap.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotRuntimeStub.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotSentinelConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotSignature.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotStackFrameReference.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotStackIntrospection.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotVMConfig.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/HotSpotVMEventListener.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/JFR.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/MetaspaceHandleObject.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/MetaspaceObject.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/SharedHotSpotSpeculationLog.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/SuppressFBWarnings.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/TranslatedException.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/UnsafeAccess.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/VMEntryPoint.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/VMField.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/VMFlag.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/VMIntrinsicMethod.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot.aarch64/src => }/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot.aarch64/src => }/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot.aarch64/src => }/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java (98%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot.aarch64/src => }/jdk/vm/ci/hotspot/aarch64/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot.amd64/src => }/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot.amd64/src => }/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot.amd64/src => }/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot.amd64/src => }/jdk/vm/ci/hotspot/amd64/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.hotspot/src => }/jdk/vm/ci/hotspot/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/AbstractJavaProfile.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/AbstractProfiledItem.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/AllocatableValue.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/Assumptions.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/Constant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/ConstantPool.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/ConstantReflectionProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/DefaultProfilingInfo.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/DeoptimizationAction.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/DeoptimizationReason.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/EncodedSpeculationReason.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/ExceptionHandler.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/InvokeTarget.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/JavaConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/JavaField.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/JavaKind.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/JavaMethod.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/JavaMethodProfile.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/JavaType.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/JavaTypeProfile.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/JavaValue.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/LineNumberTable.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/Local.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/LocalVariableTable.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/MemoryAccessProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/MetaAccessProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/MetaUtil.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/MethodHandleAccessProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/ModifiersProvider.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/NullConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/PlatformKind.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/PrimitiveConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/ProfilingInfo.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/RawConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/ResolvedJavaField.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/ResolvedJavaMethod.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/ResolvedJavaType.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/SerializableConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/Signature.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/SpeculationLog.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/SuppressFBWarnings.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/TriState.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/UnresolvedJavaField.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/UnresolvedJavaMethod.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/UnresolvedJavaType.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/VMConstant.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/Value.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/ValueKind.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.meta/src => }/jdk/vm/ci/meta/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.runtime/src => }/jdk/vm/ci/runtime/JVMCI.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.runtime/src => }/jdk/vm/ci/runtime/JVMCIBackend.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.runtime/src => }/jdk/vm/ci/runtime/JVMCICompiler.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.runtime/src => }/jdk/vm/ci/runtime/JVMCICompilerFactory.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.runtime/src => }/jdk/vm/ci/runtime/JVMCIRuntime.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.runtime/src => }/jdk/vm/ci/runtime/package-info.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.services/src => }/jdk/vm/ci/services/JVMCIPermission.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.services/src => }/jdk/vm/ci/services/JVMCIServiceLocator.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.services/src => }/jdk/vm/ci/services/Services.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.services/src => }/jdk/vm/ci/services/SuppressFBWarnings.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.services/src => }/jdk/vm/ci/services/VMEntryPoint.java (100%) rename src/jdk.internal.vm.ci/share/classes/{jdk.vm.ci.services/src => }/jdk/vm/ci/services/package-info.java (100%) diff --git a/make/modules/jdk.internal.vm.ci/Java.gmk b/make/modules/jdk.internal.vm.ci/Java.gmk index ad4991e5414..8720c97a36b 100644 --- a/make/modules/jdk.internal.vm.ci/Java.gmk +++ b/make/modules/jdk.internal.vm.ci/Java.gmk @@ -26,13 +26,5 @@ # -parameters provides method's parameters information in class file, # JVMCI compilers make use of that information for various sanity checks. # Don't use Indy strings concatenation to have good JVMCI startup performance. -# The exports are needed since JVMCI is dynamically exported (see -# jdk.vm.ci.services.internal.ReflectionAccessJDK::openJVMCITo). JAVAC_FLAGS += -parameters -XDstringConcat=inline - -## WORKAROUND jdk.internal.vm.ci source structure issue -JVMCI_MODULESOURCEPATH := $(MODULESOURCEPATH) \ - $(subst /$(MODULE)/,/*/, $(filter-out %processor/src, \ - $(wildcard $(TOPDIR)/src/$(MODULE)/share/classes/*/src))) -MODULESOURCEPATH := $(call PathList, $(JVMCI_MODULESOURCEPATH)) diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64Kind.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64Kind.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/AArch64Kind.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64Kind.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.aarch64/src/jdk/vm/ci/aarch64/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64Kind.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64Kind.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/AMD64Kind.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/AMD64Kind.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.amd64/src/jdk/vm/ci/amd64/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/amd64/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Architecture.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Architecture.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Architecture.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BailoutException.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/BailoutException.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BailoutException.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/BailoutException.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodeFrame.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/BytecodeFrame.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodeFrame.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/BytecodeFrame.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/BytecodePosition.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/BytecodePosition.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/BytecodePosition.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CPUFeatureName.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CPUFeatureName.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CPUFeatureName.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CPUFeatureName.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CallingConvention.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CallingConvention.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CallingConvention.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CallingConvention.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeCacheProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeCacheProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeCacheProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeCacheProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeUtil.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CodeUtil.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CodeUtil.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationRequest.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CompilationRequest.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationRequest.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CompilationRequest.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationRequestResult.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CompilationRequestResult.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompilationRequestResult.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CompilationRequestResult.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompiledCode.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CompiledCode.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/CompiledCode.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/CompiledCode.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/DebugInfo.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/DebugInfo.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/DebugInfo.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InstalledCode.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/InstalledCode.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InstalledCode.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/InstalledCode.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InvalidInstalledCodeException.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/InvalidInstalledCodeException.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/InvalidInstalledCodeException.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/InvalidInstalledCodeException.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Location.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Location.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Location.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Location.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/MemoryBarriers.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/MemoryBarriers.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/MemoryBarriers.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ReferenceMap.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/ReferenceMap.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ReferenceMap.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/ReferenceMap.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Register.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Register.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/Register.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/Register.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterArray.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterArray.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterArray.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterArray.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterAttributes.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterAttributes.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterAttributes.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterAttributes.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterConfig.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterConfig.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterSaveLayout.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterSaveLayout.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterSaveLayout.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterSaveLayout.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterValue.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterValue.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/RegisterValue.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/RegisterValue.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackLockValue.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/StackLockValue.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackLockValue.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/StackLockValue.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlot.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/StackSlot.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/StackSlot.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/StackSlot.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/SuppressFBWarnings.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/SuppressFBWarnings.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/SuppressFBWarnings.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/SuppressFBWarnings.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/TargetDescription.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/TargetDescription.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/TargetDescription.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/TargetDescription.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ValueKindFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/ValueKindFactory.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ValueKindFactory.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/ValueKindFactory.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ValueUtil.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/ValueUtil.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/ValueUtil.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/ValueUtil.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/VirtualObject.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/VirtualObject.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/Call.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/Call.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/Call.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/Call.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/ConstantReference.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/ConstantReference.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/ConstantReference.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/ConstantReference.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/DataPatch.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/DataPatch.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/DataPatch.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/DataPatch.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/DataSectionReference.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/DataSectionReference.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/DataSectionReference.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/DataSectionReference.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/ExceptionHandler.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/ExceptionHandler.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/ExceptionHandler.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/ExceptionHandler.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/ImplicitExceptionDispatch.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/ImplicitExceptionDispatch.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/ImplicitExceptionDispatch.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/ImplicitExceptionDispatch.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/Infopoint.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/Infopoint.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/Infopoint.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/Infopoint.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/InfopointReason.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/InfopointReason.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/InfopointReason.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/InfopointReason.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/Mark.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/Mark.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/Mark.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/Mark.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/Reference.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/Reference.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/Reference.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/Reference.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/Site.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/Site.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/Site.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/Site.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/site/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/site/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrame.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/stack/InspectedFrame.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrame.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/stack/InspectedFrame.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrameVisitor.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/stack/InspectedFrameVisitor.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/InspectedFrameVisitor.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/stack/InspectedFrameVisitor.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/StackIntrospection.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/stack/StackIntrospection.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/StackIntrospection.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/stack/StackIntrospection.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/stack/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/stack/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/code/stack/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/InitTimer.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/common/InitTimer.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/InitTimer.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/common/InitTimer.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/JVMCIError.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/common/JVMCIError.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/JVMCIError.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/common/JVMCIError.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/NativeImageReinitialize.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/common/NativeImageReinitialize.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/NativeImageReinitialize.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/common/NativeImageReinitialize.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/SuppressFBWarnings.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/common/SuppressFBWarnings.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/SuppressFBWarnings.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/common/SuppressFBWarnings.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/common/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.common/src/jdk/vm/ci/common/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/common/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Cleaner.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/Cleaner.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Cleaner.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/Cleaner.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java similarity index 99% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java index 311e644c345..3d9516737e1 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/CompilerToVM.java @@ -59,7 +59,6 @@ final class CompilerToVM { * These values mirror the equivalent values from {@code Unsafe} but are appropriate for the JVM * being compiled against. */ - // Checkstyle: stop final int ARRAY_BOOLEAN_BASE_OFFSET; final int ARRAY_BYTE_BASE_OFFSET; final int ARRAY_SHORT_BASE_OFFSET; @@ -78,7 +77,6 @@ final class CompilerToVM { final int ARRAY_FLOAT_INDEX_SCALE; final int ARRAY_DOUBLE_INDEX_SCALE; final int ARRAY_OBJECT_INDEX_SCALE; - // Checkstyle: resume @SuppressWarnings("try") CompilerToVM() { diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/DirectHotSpotObjectConstantImpl.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/EmptyEventProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/EmptyEventProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/EmptyEventProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/EmptyEventProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/EventProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/EventProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/EventProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/EventProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HandleCleaner.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HandleCleaner.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HandleCleaner.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HandleCleaner.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCallingConventionType.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCodeCacheProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompilationRequest.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompilationRequest.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompilationRequest.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompilationRequest.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompilationRequestResult.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompilationRequestResult.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompilationRequestResult.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompilationRequestResult.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCode.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledCode.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompiledNmethod.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotCompressedNullConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPool.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPool.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantPoolObject.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotConstantReflectionProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotForeignCallTarget.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotInstalledCode.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotInstalledCode.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotInstalledCode.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotInstalledCode.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJDKReflection.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJDKReflection.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIBackendFactory.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCICompilerFactory.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCICompilerFactory.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCICompilerFactory.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIReflection.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIUnsupportedOperationError.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIUnsupportedOperationError.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIUnsupportedOperationError.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCIUnsupportedOperationError.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJavaType.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJavaType.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJavaType.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMemoryAccessProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMemoryAccessProviderImpl.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaAccessProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaData.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaData.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaData.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaspaceConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMetaspaceConstantImpl.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethod.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethod.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethod.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodData.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodData.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodData.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodDataAccessor.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotMethodHandleAccessProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotModifiers.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotModifiers.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotModifiers.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotModifiers.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotNmethod.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotNmethod.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotNmethod.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantImpl.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantScope.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantScope.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotObjectConstantScope.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotObjectConstantScope.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotProfilingInfo.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotReferenceMap.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotReferenceMap.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotReferenceMap.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotReferenceMap.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaField.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaFieldImpl.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethod.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaMethodImpl.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectType.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotRuntimeStub.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotRuntimeStub.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotRuntimeStub.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotRuntimeStub.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSentinelConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotSentinelConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSentinelConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotSentinelConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotSignature.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSignature.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotSignature.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotSpeculationLog.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotStackFrameReference.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotStackFrameReference.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotStackFrameReference.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotStackFrameReference.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotStackIntrospection.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotStackIntrospection.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotStackIntrospection.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotStackIntrospection.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfigAccess.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfigStore.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMEventListener.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMEventListener.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMEventListener.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMEventListener.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/IndirectHotSpotObjectConstantImpl.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/JFR.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/JFR.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/JFR.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/JFR.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceHandleObject.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/MetaspaceHandleObject.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceHandleObject.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/MetaspaceHandleObject.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceObject.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/MetaspaceObject.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/MetaspaceObject.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/MetaspaceObject.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SharedHotSpotSpeculationLog.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedHotSpotSpeculationLog.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SharedHotSpotSpeculationLog.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedHotSpotSpeculationLog.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SharedLibraryJVMCIReflection.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SuppressFBWarnings.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SuppressFBWarnings.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SuppressFBWarnings.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/SuppressFBWarnings.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/TranslatedException.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/TranslatedException.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/TranslatedException.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/UnsafeAccess.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/UnsafeAccess.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/UnsafeAccess.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMEntryPoint.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/VMEntryPoint.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMEntryPoint.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/VMEntryPoint.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/VMField.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMField.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/VMField.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMFlag.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/VMFlag.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMFlag.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/VMFlag.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMIntrinsicMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/VMIntrinsicMethod.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/VMIntrinsicMethod.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/VMIntrinsicMethod.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotRegisterConfig.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java similarity index 98% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java index fa28dacc6e5..d9fb914d8ab 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java @@ -58,7 +58,6 @@ class AArch64HotSpotVMConfig extends HotSpotVMConfigAccess { /* * These flags are set if the corresponding support is in the hardware. */ - // Checkstyle: stop final long aarch64FP = getConstant("VM_Version::CPU_FP", Long.class); final long aarch64ASIMD = getConstant("VM_Version::CPU_ASIMD", Long.class); final long aarch64EVTSTRM = getConstant("VM_Version::CPU_EVTSTRM", Long.class); @@ -70,5 +69,4 @@ class AArch64HotSpotVMConfig extends HotSpotVMConfigAccess { final long aarch64LSE = getConstant("VM_Version::CPU_LSE", Long.class); final long aarch64STXR_PREFETCH = getConstant("VM_Version::CPU_STXR_PREFETCH", Long.class); final long aarch64A53MAC = getConstant("VM_Version::CPU_A53MAC", Long.class); - // Checkstyle: resume } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.aarch64/src/jdk/vm/ci/hotspot/aarch64/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotJVMCIBackendFactory.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotRegisterConfig.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/AMD64HotSpotVMConfig.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot.amd64/src/jdk/vm/ci/hotspot/amd64/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/amd64/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractJavaProfile.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AbstractJavaProfile.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractJavaProfile.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AbstractJavaProfile.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractProfiledItem.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AbstractProfiledItem.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AbstractProfiledItem.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AbstractProfiledItem.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AllocatableValue.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AllocatableValue.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/AllocatableValue.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/AllocatableValue.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Assumptions.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Assumptions.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Assumptions.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Assumptions.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Constant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Constant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Constant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantPool.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantPool.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantPool.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantReflectionProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ConstantReflectionProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ConstantReflectionProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DefaultProfilingInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DefaultProfilingInfo.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DefaultProfilingInfo.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DefaultProfilingInfo.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationAction.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DeoptimizationAction.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationAction.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DeoptimizationAction.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DeoptimizationReason.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/DeoptimizationReason.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/DeoptimizationReason.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/EncodedSpeculationReason.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EncodedSpeculationReason.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/EncodedSpeculationReason.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/EncodedSpeculationReason.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ExceptionHandler.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ExceptionHandler.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ExceptionHandler.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ExceptionHandler.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/InvokeTarget.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/InvokeTarget.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/InvokeTarget.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaField.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaField.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaField.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaKind.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaKind.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaMethod.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethod.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaMethod.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethodProfile.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaMethodProfile.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaMethodProfile.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaMethodProfile.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaType.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaType.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaType.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaTypeProfile.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaTypeProfile.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaTypeProfile.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaTypeProfile.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaValue.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaValue.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/JavaValue.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaValue.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTable.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/LineNumberTable.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LineNumberTable.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/LineNumberTable.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Local.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Local.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Local.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Local.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTable.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/LocalVariableTable.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/LocalVariableTable.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/LocalVariableTable.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MemoryAccessProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MemoryAccessProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MemoryAccessProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaAccessProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaAccessProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaUtil.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MetaUtil.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MetaUtil.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/MethodHandleAccessProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/MethodHandleAccessProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ModifiersProvider.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ModifiersProvider.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ModifiersProvider.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ModifiersProvider.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/NullConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/NullConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/NullConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/NullConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PlatformKind.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/PlatformKind.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PlatformKind.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/PlatformKind.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PrimitiveConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/PrimitiveConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/PrimitiveConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/PrimitiveConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ProfilingInfo.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ProfilingInfo.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ProfilingInfo.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/RawConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/RawConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/RawConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/RawConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaField.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaField.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaMethod.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ResolvedJavaType.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaType.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SerializableConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/SerializableConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SerializableConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/SerializableConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Signature.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Signature.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Signature.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Signature.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/SpeculationLog.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SpeculationLog.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/SpeculationLog.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SuppressFBWarnings.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/SuppressFBWarnings.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/SuppressFBWarnings.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/SuppressFBWarnings.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TriState.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/TriState.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/TriState.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/TriState.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/UnresolvedJavaField.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaField.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/UnresolvedJavaField.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaField.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/UnresolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaMethod.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/UnresolvedJavaMethod.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaMethod.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/UnresolvedJavaType.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaType.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/UnresolvedJavaType.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/UnresolvedJavaType.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/VMConstant.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/VMConstant.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/VMConstant.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Value.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Value.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/Value.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/Value.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ValueKind.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ValueKind.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/ValueKind.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ValueKind.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCI.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCI.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCI.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCI.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIBackend.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCIBackend.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIBackend.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCIBackend.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCICompiler.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCICompiler.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCICompiler.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCICompiler.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCICompilerFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCICompilerFactory.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCICompilerFactory.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCICompilerFactory.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIRuntime.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCIRuntime.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/JVMCIRuntime.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/JVMCIRuntime.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.runtime/src/jdk/vm/ci/runtime/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/runtime/package-info.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIPermission.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/JVMCIPermission.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIPermission.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/JVMCIPermission.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIServiceLocator.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/JVMCIServiceLocator.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIServiceLocator.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/JVMCIServiceLocator.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/Services.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/SuppressFBWarnings.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/SuppressFBWarnings.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/SuppressFBWarnings.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/SuppressFBWarnings.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/VMEntryPoint.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/VMEntryPoint.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/VMEntryPoint.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/VMEntryPoint.java diff --git a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/package-info.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/package-info.java similarity index 100% rename from src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/package-info.java rename to src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/services/package-info.java From 4554f82c84575996e660da9962cbb433ab9c33a3 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:34:20 +0000 Subject: [PATCH 070/217] 8303482: Update LCMS to 2.15 Backport-of: c073ef2ed59483c8dccec9fcac930c862885ff91 --- src/java.desktop/share/legal/lcms.md | 13 +++++++------ src/java.desktop/share/native/liblcms/cmsalpha.c | 2 +- src/java.desktop/share/native/liblcms/cmscam02.c | 4 ++-- src/java.desktop/share/native/liblcms/cmscgats.c | 10 ++++++---- src/java.desktop/share/native/liblcms/cmscnvrt.c | 10 +++++----- src/java.desktop/share/native/liblcms/cmserr.c | 2 +- src/java.desktop/share/native/liblcms/cmsgamma.c | 6 +++++- src/java.desktop/share/native/liblcms/cmshalf.c | 2 +- src/java.desktop/share/native/liblcms/cmsintrp.c | 2 +- src/java.desktop/share/native/liblcms/cmsio0.c | 8 ++++---- src/java.desktop/share/native/liblcms/cmsio1.c | 6 +++++- src/java.desktop/share/native/liblcms/cmslut.c | 2 +- src/java.desktop/share/native/liblcms/cmsmd5.c | 2 +- src/java.desktop/share/native/liblcms/cmsmtrx.c | 2 +- src/java.desktop/share/native/liblcms/cmsnamed.c | 12 ++++++++++-- src/java.desktop/share/native/liblcms/cmsopt.c | 6 +++++- src/java.desktop/share/native/liblcms/cmspack.c | 10 +++++----- src/java.desktop/share/native/liblcms/cmspcs.c | 2 +- .../share/native/liblcms/cmsplugin.c | 16 +++++++++------- src/java.desktop/share/native/liblcms/cmsps2.c | 2 +- src/java.desktop/share/native/liblcms/cmssamp.c | 7 +++---- src/java.desktop/share/native/liblcms/cmssm.c | 2 +- src/java.desktop/share/native/liblcms/cmstypes.c | 14 ++++++++++++-- src/java.desktop/share/native/liblcms/cmsvirt.c | 2 +- src/java.desktop/share/native/liblcms/cmswtpnt.c | 7 +++++-- src/java.desktop/share/native/liblcms/cmsxform.c | 2 +- src/java.desktop/share/native/liblcms/lcms2.h | 8 ++++---- .../share/native/liblcms/lcms2_internal.h | 3 +-- .../share/native/liblcms/lcms2_plugin.h | 2 +- 29 files changed, 101 insertions(+), 65 deletions(-) diff --git a/src/java.desktop/share/legal/lcms.md b/src/java.desktop/share/legal/lcms.md index 1576edb8db6..da86a9c47ca 100644 --- a/src/java.desktop/share/legal/lcms.md +++ b/src/java.desktop/share/legal/lcms.md @@ -1,8 +1,7 @@ -## Little Color Management System (LCMS) v2.14 +## Little Color Management System (LCMS) v2.15 ### LCMS License
-
 README.1ST file information
 
 LittleCMS core is released under MIT License
@@ -10,7 +9,7 @@ LittleCMS core is released under MIT License
 ---------------------------------
 
 Little CMS
-Copyright (c) 1998-2022 Marti Maria Saguer
+Copyright (c) 1998-2023 Marti Maria Saguer
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
@@ -32,7 +31,6 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 ---------------------------------
-
 The below license applies to the following files:
 liblcms/cmssm.c
 
@@ -44,12 +42,12 @@ SoftSurfer makes no warranty for this code, and cannot be held
 liable for any real or imagined damage resulting from its use.
 Users of this code must verify correctness for their application.
 
-
 
### AUTHORS File Information ``` + Main Author ------------ Marti Maria @@ -90,11 +88,15 @@ Mark Allen Noel Carboni Sergei Trofimovic Philipp Knechtges +Amyspark +Lovell Fuller +Eli Schwartz Special Thanks -------------- Artifex software AlienSkin software +libVIPS Jan Morovic Jos Vernon (WebSupergoo) Harald Schneider (Maxon) @@ -103,5 +105,4 @@ Dimitrios Anastassakis Lemke Software Tim Zaman - ``` diff --git a/src/java.desktop/share/native/liblcms/cmsalpha.c b/src/java.desktop/share/native/liblcms/cmsalpha.c index c6a37e79727..e69259e8a51 100644 --- a/src/java.desktop/share/native/liblcms/cmsalpha.c +++ b/src/java.desktop/share/native/liblcms/cmsalpha.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmscam02.c b/src/java.desktop/share/native/liblcms/cmscam02.c index 23f12419676..71a48d43de4 100644 --- a/src/java.desktop/share/native/liblcms/cmscam02.c +++ b/src/java.desktop/share/native/liblcms/cmscam02.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -353,7 +353,7 @@ CAM02COLOR HPEtoCAT02(CAM02COLOR clr) M[5] = ((-0.7036 * 0.201908) + (1.6975 * 0.000008) + 0.0061); M[6] = (( 0.0030 * 1.910197) + (0.0136 * 0.370950)); M[7] = (( 0.0030 * -1.112124) + (0.0136 * 0.629054)); - M[8] = (( 0.0030 * 0.201908) + (0.0136 * 0.000008) + 0.9834);; + M[8] = (( 0.0030 * 0.201908) + (0.0136 * 0.000008) + 0.9834); clr.RGBc[0] = (clr.RGBp[0] * M[0]) + (clr.RGBp[1] * M[1]) + (clr.RGBp[2] * M[2]); clr.RGBc[1] = (clr.RGBp[0] * M[3]) + (clr.RGBp[1] * M[4]) + (clr.RGBp[2] * M[5]); diff --git a/src/java.desktop/share/native/liblcms/cmscgats.c b/src/java.desktop/share/native/liblcms/cmscgats.c index 61d5533e540..9d0aea27d73 100644 --- a/src/java.desktop/share/native/liblcms/cmscgats.c +++ b/src/java.desktop/share/native/liblcms/cmscgats.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1968,13 +1968,15 @@ cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* memset(&sd, 0, sizeof(sd)); sd.stream = NULL; - sd.Base = (cmsUInt8Number*) MemPtr; + sd.Base = (cmsUInt8Number*) MemPtr; sd.Ptr = sd.Base; sd.Used = 0; - if (sd.Base) - sd.Max = *BytesNeeded; // Write to memory? + if (sd.Base && (*BytesNeeded > 0)) { + + sd.Max = (*BytesNeeded) - 1; // Write to memory? + } else sd.Max = 0; // Just counting the needed bytes diff --git a/src/java.desktop/share/native/liblcms/cmscnvrt.c b/src/java.desktop/share/native/liblcms/cmscnvrt.c index 535a9e12d7e..b73d594f2ec 100644 --- a/src/java.desktop/share/native/liblcms/cmscnvrt.c +++ b/src/java.desktop/share/native/liblcms/cmscnvrt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -399,11 +399,11 @@ cmsBool ComputeConversion(cmsUInt32Number i, cmsCIEXYZ WhitePointIn, WhitePointOut; cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut; - _cmsReadMediaWhitePoint(&WhitePointIn, hProfiles[i-1]); - _cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i-1]); + if (!_cmsReadMediaWhitePoint(&WhitePointIn, hProfiles[i - 1])) return FALSE; + if (!_cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i - 1])) return FALSE; - _cmsReadMediaWhitePoint(&WhitePointOut, hProfiles[i]); - _cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i]); + if (!_cmsReadMediaWhitePoint(&WhitePointOut, hProfiles[i])) return FALSE; + if (!_cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i])) return FALSE; if (!ComputeAbsoluteIntent(AdaptationState, &WhitePointIn, &ChromaticAdaptationMatrixIn, diff --git a/src/java.desktop/share/native/liblcms/cmserr.c b/src/java.desktop/share/native/liblcms/cmserr.c index 772a0a169e5..739cc0b2c98 100644 --- a/src/java.desktop/share/native/liblcms/cmserr.c +++ b/src/java.desktop/share/native/liblcms/cmserr.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmsgamma.c b/src/java.desktop/share/native/liblcms/cmsgamma.c index b5fd47a8ed1..08409434064 100644 --- a/src/java.desktop/share/native/liblcms/cmsgamma.c +++ b/src/java.desktop/share/native/liblcms/cmsgamma.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -852,6 +852,10 @@ cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cm { cmsCurveSegment Seg[3]; + // Do some housekeeping + if (nEntries == 0 || values == NULL) + return NULL; + // A segmented tone curve should have function segments in the first and last positions // Initialize segmented curve part up to 0 to constant value = samples[0] Seg[0].x0 = MINUS_INF; diff --git a/src/java.desktop/share/native/liblcms/cmshalf.c b/src/java.desktop/share/native/liblcms/cmshalf.c index eb1d4aa6ea1..5babb063eb0 100644 --- a/src/java.desktop/share/native/liblcms/cmshalf.c +++ b/src/java.desktop/share/native/liblcms/cmshalf.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmsintrp.c b/src/java.desktop/share/native/liblcms/cmsintrp.c index 7fe74feafd0..9837454df0b 100644 --- a/src/java.desktop/share/native/liblcms/cmsintrp.c +++ b/src/java.desktop/share/native/liblcms/cmsintrp.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmsio0.c b/src/java.desktop/share/native/liblcms/cmsio0.c index 8d0c014c0fe..6763970f619 100644 --- a/src/java.desktop/share/native/liblcms/cmsio0.c +++ b/src/java.desktop/share/native/liblcms/cmsio0.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1951,7 +1951,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si if (data != NULL) { if (BufferSize < TagSize) - goto Error; + TagSize = BufferSize; if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error; if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error; @@ -1964,7 +1964,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si return Icc ->TagSizes[i]; } - // The data has been already read, or written. But wait!, maybe the user chose to save as + // The data has been already read, or written. But wait!, maybe the user choose to save as // raw data. In this case, return the raw data directly if (Icc ->TagSaveAsRaw[i]) { @@ -1973,7 +1973,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si TagSize = Icc ->TagSizes[i]; if (BufferSize < TagSize) - goto Error; + TagSize = BufferSize; memmove(data, Icc ->TagPtrs[i], TagSize); diff --git a/src/java.desktop/share/native/liblcms/cmsio1.c b/src/java.desktop/share/native/liblcms/cmsio1.c index 85d9f6788b5..bd8a832ac40 100644 --- a/src/java.desktop/share/native/liblcms/cmsio1.c +++ b/src/java.desktop/share/native/liblcms/cmsio1.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -880,6 +880,10 @@ cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUI return FALSE; } + // Extended intents are not strictly CLUT-based + if (Intent > INTENT_ABSOLUTE_COLORIMETRIC) + return FALSE; + return cmsIsTag(hProfile, TagTable[Intent]); } diff --git a/src/java.desktop/share/native/liblcms/cmslut.c b/src/java.desktop/share/native/liblcms/cmslut.c index 457ab6ecf5c..24114632ad0 100644 --- a/src/java.desktop/share/native/liblcms/cmslut.c +++ b/src/java.desktop/share/native/liblcms/cmslut.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmsmd5.c b/src/java.desktop/share/native/liblcms/cmsmd5.c index ea97c0d8774..01aa44de85a 100644 --- a/src/java.desktop/share/native/liblcms/cmsmd5.c +++ b/src/java.desktop/share/native/liblcms/cmsmd5.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmsmtrx.c b/src/java.desktop/share/native/liblcms/cmsmtrx.c index 9bbe82871f5..599c290bd70 100644 --- a/src/java.desktop/share/native/liblcms/cmsmtrx.c +++ b/src/java.desktop/share/native/liblcms/cmsmtrx.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmsnamed.c b/src/java.desktop/share/native/liblcms/cmsnamed.c index c710ba39372..04280180230 100644 --- a/src/java.desktop/share/native/liblcms/cmsnamed.c +++ b/src/java.desktop/share/native/liblcms/cmsnamed.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -399,6 +399,8 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, if (len != NULL) *len = v ->Len; + if (v->StrW + v->Len > mlu->PoolSize) return NULL; + return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); } @@ -790,7 +792,13 @@ cmsStage* CMSEXPORT _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform) { _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; - cmsStage* mpe = v ->Lut->Elements; + cmsStage* mpe; + + if (v == NULL) return NULL; + if (v->Lut == NULL) return NULL; + + mpe = v->Lut->Elements; + if (mpe == NULL) return NULL; if (mpe ->Type != cmsSigNamedColorElemType) return NULL; return (cmsNAMEDCOLORLIST*) mpe ->Data; diff --git a/src/java.desktop/share/native/liblcms/cmsopt.c b/src/java.desktop/share/native/liblcms/cmsopt.c index e32f73b86ee..3e81ae1df1b 100644 --- a/src/java.desktop/share/native/liblcms/cmsopt.c +++ b/src/java.desktop/share/native/liblcms/cmsopt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1724,6 +1724,10 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 _cmsStageMatrixData* Data1 = (_cmsStageMatrixData*)cmsStageData(Matrix1); _cmsStageMatrixData* Data2 = (_cmsStageMatrixData*)cmsStageData(Matrix2); + // Only RGB to RGB + if (Matrix1->InputChannels != 3 || Matrix1->OutputChannels != 3 || + Matrix2->InputChannels != 3 || Matrix2->OutputChannels != 3) return FALSE; + // Input offset should be zero if (Data1->Offset != NULL) return FALSE; diff --git a/src/java.desktop/share/native/liblcms/cmspack.c b/src/java.desktop/share/native/liblcms/cmspack.c index e90e45656fc..da5fc6019d3 100644 --- a/src/java.desktop/share/native/liblcms/cmspack.c +++ b/src/java.desktop/share/native/liblcms/cmspack.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1736,7 +1736,7 @@ cmsUInt8Number* PackChunkyBytes(CMSREGISTER _cmsTRANSFORM* info, if (Reverse) v = REVERSE_FLAVOR_16(v); - if (Premul && alpha_factor != 0) + if (Premul) { v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); } @@ -1805,7 +1805,7 @@ cmsUInt8Number* PackChunkyWords(CMSREGISTER _cmsTRANSFORM* info, if (Reverse) v = REVERSE_FLAVOR_16(v); - if (Premul && alpha_factor != 0) + if (Premul) { v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); } @@ -1872,7 +1872,7 @@ cmsUInt8Number* PackPlanarBytes(CMSREGISTER _cmsTRANSFORM* info, if (Reverse) v = REVERSE_FLAVOR_16(v); - if (Premul && alpha_factor != 0) + if (Premul) { v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); } @@ -1932,7 +1932,7 @@ cmsUInt8Number* PackPlanarWords(CMSREGISTER _cmsTRANSFORM* info, if (Reverse) v = REVERSE_FLAVOR_16(v); - if (Premul && alpha_factor != 0) + if (Premul) { v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); } diff --git a/src/java.desktop/share/native/liblcms/cmspcs.c b/src/java.desktop/share/native/liblcms/cmspcs.c index f17c74b4b2d..c4739840053 100644 --- a/src/java.desktop/share/native/liblcms/cmspcs.c +++ b/src/java.desktop/share/native/liblcms/cmspcs.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmsplugin.c b/src/java.desktop/share/native/liblcms/cmsplugin.c index 87c74390bdb..c2808bb9278 100644 --- a/src/java.desktop/share/native/liblcms/cmsplugin.c +++ b/src/java.desktop/share/native/liblcms/cmsplugin.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -825,8 +825,6 @@ void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc) // identify which plug-in to unregister. void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID) { - struct _cmsContext_struct* ctx = _cmsGetContext(ContextID); - _cmsRegisterMemHandlerPlugin(ContextID, NULL); _cmsRegisterInterpPlugin(ContextID, NULL); _cmsRegisterTagTypePlugin(ContextID, NULL); @@ -840,9 +838,6 @@ void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID) _cmsRegisterMutexPlugin(ContextID, NULL); _cmsRegisterParallelizationPlugin(ContextID, NULL); - if (ctx->MemPool != NULL) - _cmsSubAllocDestroy(ctx->MemPool); - ctx->MemPool = NULL; } @@ -1010,7 +1005,14 @@ cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) // The ContextID can no longer be used in any THR operation. void CMSEXPORT cmsDeleteContext(cmsContext ContextID) { - if (ContextID != NULL) { + if (ContextID == NULL) { + + cmsUnregisterPlugins(); + if (globalContext.MemPool != NULL) + _cmsSubAllocDestroy(globalContext.MemPool); + globalContext.MemPool = NULL; + } + else { struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID; struct _cmsContext_struct fakeContext; diff --git a/src/java.desktop/share/native/liblcms/cmsps2.c b/src/java.desktop/share/native/liblcms/cmsps2.c index c0816347d24..537f6854067 100644 --- a/src/java.desktop/share/native/liblcms/cmsps2.c +++ b/src/java.desktop/share/native/liblcms/cmsps2.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmssamp.c b/src/java.desktop/share/native/liblcms/cmssamp.c index cf4a13968d1..8a01f7ec685 100644 --- a/src/java.desktop/share/native/liblcms/cmssamp.c +++ b/src/java.desktop/share/native/liblcms/cmssamp.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -152,10 +152,9 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, // Convert black to Lab cmsDoTransform(xform, Black, &Lab, 1); - // Force it to be neutral, clip to max. L* of 50 + // Force it to be neutral, check for inconsistences Lab.a = Lab.b = 0; - if (Lab.L > 50) Lab.L = 50; - if (Lab.L < 0) Lab.L = 0; + if (Lab.L > 50 || Lab.L < 0) Lab.L = 0; // Free the resources cmsDeleteTransform(xform); diff --git a/src/java.desktop/share/native/liblcms/cmssm.c b/src/java.desktop/share/native/liblcms/cmssm.c index 4300d164df6..3e1486ae3ae 100644 --- a/src/java.desktop/share/native/liblcms/cmssm.c +++ b/src/java.desktop/share/native/liblcms/cmssm.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmstypes.c b/src/java.desktop/share/native/liblcms/cmstypes.c index 898b5e8ffd6..7b07b6b9cf4 100644 --- a/src/java.desktop/share/native/liblcms/cmstypes.c +++ b/src/java.desktop/share/native/liblcms/cmstypes.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1549,6 +1549,12 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU if (!_cmsReadUInt32Number(io, &Len)) goto Error; if (!_cmsReadUInt32Number(io, &Offset)) goto Error; + // Offset MUST be even because it indexes a block of utf16 chars. + // Tricky profiles that uses odd positions will not work anyway + // because the whole utf16 block is previously converted to wchar_t + // and sizeof this type may be of 4 bytes. On Linux systems, for example. + if (Offset & 1) goto Error; + // Check for overflow if (Offset < (SizeOfHeader + 8)) goto Error; if (((Offset + Len) < Len) || ((Offset + Len) > SizeOfTag + 8)) goto Error; @@ -1576,8 +1582,12 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU } else { - Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag); + // Make sure this is an even utf16 size. + if (SizeOfTag & 1) goto Error; + + Block = (wchar_t*) _cmsCalloc(self ->ContextID, 1, SizeOfTag); if (Block == NULL) goto Error; + NumOfWchar = SizeOfTag / sizeof(wchar_t); if (!_cmsReadWCharArray(io, NumOfWchar, Block)) { _cmsFree(self->ContextID, Block); diff --git a/src/java.desktop/share/native/liblcms/cmsvirt.c b/src/java.desktop/share/native/liblcms/cmsvirt.c index 6d15f1fde13..6ce04796174 100644 --- a/src/java.desktop/share/native/liblcms/cmsvirt.c +++ b/src/java.desktop/share/native/liblcms/cmsvirt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/cmswtpnt.c b/src/java.desktop/share/native/liblcms/cmswtpnt.c index 96bad5de7ca..27d71803531 100644 --- a/src/java.desktop/share/native/liblcms/cmswtpnt.c +++ b/src/java.desktop/share/native/liblcms/cmswtpnt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -244,12 +244,15 @@ cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion, _cmsMAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ); _cmsMAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ); + if ((fabs(ConeSourceRGB.n[0]) < MATRIX_DET_TOLERANCE) || + (fabs(ConeSourceRGB.n[1]) < MATRIX_DET_TOLERANCE) || + (fabs(ConeSourceRGB.n[2]) < MATRIX_DET_TOLERANCE)) return FALSE; + // Build matrix _cmsVEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0); _cmsVEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0); _cmsVEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]); - // Normalize _cmsMAT3per(&Tmp, &Cone, Chad); _cmsMAT3per(Conversion, &Chad_Inv, &Tmp); diff --git a/src/java.desktop/share/native/liblcms/cmsxform.c b/src/java.desktop/share/native/liblcms/cmsxform.c index 8b8f831f0af..3f3ad28c6c4 100644 --- a/src/java.desktop/share/native/liblcms/cmsxform.c +++ b/src/java.desktop/share/native/liblcms/cmsxform.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/lcms2.h b/src/java.desktop/share/native/liblcms/lcms2.h index ab122f3b342..d5b8c477f23 100644 --- a/src/java.desktop/share/native/liblcms/lcms2.h +++ b/src/java.desktop/share/native/liblcms/lcms2.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -52,7 +52,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.14 +// Version 2.15 // #ifndef _lcms2_H @@ -110,7 +110,7 @@ extern "C" { #endif // Version/release -#define LCMS_VERSION 2140 +#define LCMS_VERSION 2150 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED @@ -256,7 +256,7 @@ typedef int cmsBool; // Calling convention -- this is hardly platform and compiler dependent -#ifdef CMS_IS_WINDOWS_ +#if defined(CMS_IS_WINDOWS_) && !defined(__GNUC__) # if defined(CMS_DLL) || defined(CMS_DLL_BUILD) # ifdef __BORLANDC__ # define CMSEXPORT __stdcall _export diff --git a/src/java.desktop/share/native/liblcms/lcms2_internal.h b/src/java.desktop/share/native/liblcms/lcms2_internal.h index 3999e24d771..4c29a6c0218 100644 --- a/src/java.desktop/share/native/liblcms/lcms2_internal.h +++ b/src/java.desktop/share/native/liblcms/lcms2_internal.h @@ -27,10 +27,9 @@ // However, the following notice accompanied the original version of this // file: // - // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/src/java.desktop/share/native/liblcms/lcms2_plugin.h b/src/java.desktop/share/native/liblcms/lcms2_plugin.h index 1dc1a4661e2..e7e7bd1f0ce 100644 --- a/src/java.desktop/share/native/liblcms/lcms2_plugin.h +++ b/src/java.desktop/share/native/liblcms/lcms2_plugin.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), From 06b764ce279dc3d9fbdb844c6d6a2716999a5779 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:35:54 +0000 Subject: [PATCH 071/217] 8304134: jib bootstrapper fails to quote filename when checking download filetype Backport-of: 75168eaca3f665785519bb489073962a4972fdc0 --- bin/jib.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/jib.sh b/bin/jib.sh index 254f09ada1c..9f34cf9ab7b 100644 --- a/bin/jib.sh +++ b/bin/jib.sh @@ -130,7 +130,7 @@ install_jib() { fi # Want to check the filetype using file, to see if we got served a HTML error page. # This is sensitive to the filename containing a specific string, but good enough. - file ${installed_jib_script}.gz | grep "gzip compressed data" > /dev/null + file "${installed_jib_script}.gz" | grep "gzip compressed data" > /dev/null if [ $? -ne 0 ]; then echo "Warning: ${installed_jib_script}.gz is not a gzip file." echo "If you are behind a proxy you may need to configure exceptions using no_proxy." From 8f10b354c7942ccee3c6becf537cf378a5133eb1 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:42:04 +0000 Subject: [PATCH 072/217] 8304683: Memory leak in WB_IsMethodCompatible Backport-of: 760c0128a4ef787c8c8addb26894c072ba8b2eb1 --- src/hotspot/share/prims/whitebox.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 296bfe9e49c..f6c947f13e7 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -821,10 +821,9 @@ static bool is_excluded_for_compiler(AbstractCompiler* comp, methodHandle& mh) { return true; } DirectiveSet* directive = DirectivesStack::getMatchingDirective(mh, comp); - if (directive->ExcludeOption) { - return true; - } - return false; + bool exclude = directive->ExcludeOption; + DirectivesStack::release(directive); + return exclude; } static bool can_be_compiled_at_level(methodHandle& mh, jboolean is_osr, int level) { From a370ca62b3101eb4795468747e02e59cbce5ff64 Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Thu, 20 Apr 2023 08:47:55 +0000 Subject: [PATCH 073/217] 8305400: ISO 4217 Amendment 175 Update Backport-of: 7cf24d1c06142a3bab9cce5cd0ba34b8bbccf00f --- make/data/currency/CurrencyData.properties | 4 ++-- test/jdk/java/util/Currency/tablea1.txt | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/make/data/currency/CurrencyData.properties b/make/data/currency/CurrencyData.properties index d234c96c476..12c0c69801e 100644 --- a/make/data/currency/CurrencyData.properties +++ b/make/data/currency/CurrencyData.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2000, 2022, 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 @@ -32,7 +32,7 @@ formatVersion=3 # Version of the currency code information in this class. # It is a serial number that accompanies with each amendment. -dataVersion=174 +dataVersion=175 # List of all valid ISO 4217 currency codes. # To ensure compatibility, do not remove codes. diff --git a/test/jdk/java/util/Currency/tablea1.txt b/test/jdk/java/util/Currency/tablea1.txt index 3eef0eba00e..4e33a62c05e 100644 --- a/test/jdk/java/util/Currency/tablea1.txt +++ b/test/jdk/java/util/Currency/tablea1.txt @@ -1,12 +1,12 @@ # # -# Amendments up until ISO 4217 AMENDMENT NUMBER 174 -# (As of 2 November 2022) +# Amendments up until ISO 4217 AMENDMENT NUMBER 175 +# (As of 31 March 2023) # # Version FILEVERSION=3 -DATAVERSION=174 +DATAVERSION=175 # ISO 4217 currency data AF AFN 971 2 From 9d6f1d716ef13987cf4b36b6072b33d1c1aa5522 Mon Sep 17 00:00:00 2001 From: Andrei Pangin Date: Thu, 20 Apr 2023 11:12:26 +0000 Subject: [PATCH 074/217] 8201516: DebugNonSafepoints generates incorrect information Reviewed-by: thartmann, shade Backport-of: 94eda53d98e5011cc613d031ff8941e254eb666b --- src/hotspot/share/opto/parse1.cpp | 6 +- src/hotspot/share/opto/phaseX.cpp | 13 ++ .../compiler/c2/irTests/TestDebugInfo.java | 135 ++++++++++++++++++ 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 test/hotspot/jtreg/compiler/c2/irTests/TestDebugInfo.java diff --git a/src/hotspot/share/opto/parse1.cpp b/src/hotspot/share/opto/parse1.cpp index 7819812e1fe..c895f12354f 100644 --- a/src/hotspot/share/opto/parse1.cpp +++ b/src/hotspot/share/opto/parse1.cpp @@ -613,8 +613,6 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) // Parse all the basic blocks. do_all_blocks(); - C->set_default_node_notes(caller_nn); - // Check for bailouts during conversion to graph if (failing()) { if (log) log->done("parse"); @@ -625,6 +623,10 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses) set_map(entry_map); do_exits(); + // Only reset this now, to make sure that debug information emitted + // for exiting control flow still refers to the inlined method. + C->set_default_node_notes(caller_nn); + if (log) log->done("parse nodes='%d' live='%d' memory='" SIZE_FORMAT "'", C->unique(), C->live_nodes(), C->node_arena()->used()); } diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index bb14fcaac6b..f39f07e7e7f 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -469,6 +469,14 @@ PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn, uint worklist_size = worklist->size(); + GrowableArray* old_node_note_array = C->node_note_array(); + if (old_node_note_array != nullptr) { + int new_size = (_useful.size() >> 8) + 1; // The node note array uses blocks, see C->_log2_node_notes_block_size + new_size = MAX2(8, new_size); + C->set_node_note_array(new (C->comp_arena()) GrowableArray (C->comp_arena(), new_size, 0, nullptr)); + C->grow_node_notes(C->node_note_array(), new_size); + } + // Iterate over the set of live nodes. for (uint current_idx = 0; current_idx < _useful.size(); current_idx++) { Node* n = _useful.at(current_idx); @@ -484,6 +492,11 @@ PhaseRenumberLive::PhaseRenumberLive(PhaseGVN* gvn, assert(_old2new_map.at(n->_idx) == -1, "already seen"); _old2new_map.at_put(n->_idx, current_idx); + if (old_node_note_array != nullptr) { + Node_Notes* nn = C->locate_node_notes(old_node_note_array, n->_idx); + C->set_node_notes_at(current_idx, nn); + } + n->set_idx(current_idx); // Update node ID. if (in_worklist) { diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestDebugInfo.java b/test/hotspot/jtreg/compiler/c2/irTests/TestDebugInfo.java new file mode 100644 index 00000000000..9facd69ca2d --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestDebugInfo.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 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 + * 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 compiler.c2.irTests; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8201516 + * @summary Verify that debug information in C2 compiled code is correct. + * @library /test/lib / + * @requires vm.compiler2.enabled + * @run driver compiler.c2.irTests.TestDebugInfo + */ +public class TestDebugInfo { + + public static void main(String[] args) { + TestFramework.runWithFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:+DebugNonSafepoints"); + } + + static class MyClass { + final int val; + + @ForceInline + public MyClass(int val) { + this.val = val; + } + + @ForceInline + synchronized void synchronizedMethod(boolean throwIt) { + if (throwIt) { + throw new RuntimeException(); // Make sure there is an exception state + } + } + } + + static Object[] array = new Object[3]; + static MyClass myVal = new MyClass(42); + + // Verify that the MemBarRelease emitted at the MyClass constructor exit + // does not incorrectly reference the caller method in its debug information. + @Test + @IR(failOn = {"MemBarRelease.*testFinalFieldInit.*bci:-1"}) + public static void testFinalFieldInit() { + array[0] = new MyClass(42); + array[1] = new MyClass(42); + array[2] = new MyClass(42); + } + + // Verify that the MemBarReleaseLock emitted at the synchronizedMethod exit + // does not incorrectly reference the caller method in its debug information. + @Test + @IR(failOn = {"MemBarReleaseLock.*testSynchronized.*bci:-1"}) + public static void testSynchronized() { + try { + myVal.synchronizedMethod(false); + myVal.synchronizedMethod(true); + } catch (Exception e) { + // Ignore + } + } + + static byte b0 = 0; + static byte b1 = 0; + static byte b2 = 0; + static byte b3 = 0; + + @ForceInline + public static Integer useless3(Integer val) { + return ++val; + } + + @ForceInline + public static Integer useless2(Integer val) { + return useless3(useless3(useless3(useless3(useless3(useless3(useless3(useless3(val)))))))); + } + + @ForceInline + public static Integer useless1(Integer val) { + return useless2(useless2(useless2(useless2(useless2(useless2(useless2(useless2(val)))))))); + } + + @ForceInline + public static void useful3() { + b3 = 3; + } + + @ForceInline + public static void useful2() { + useful3(); + b2 = 2; + } + + @ForceInline + public static void useful1() { + useful2(); + b1 = 1; + } + + // Verify that RenumberLiveNodes preserves the debug information side table. + @Test + @IR(counts = {"StoreB.*name=b3.*useful3.*bci:1.*useful2.*bci:0.*useful1.*bci:0.*testRenumberLiveNodes.*bci:9", "= 1"}) + @IR(counts = {"StoreB.*name=b2.*useful2.*bci:4.*useful1.*bci:0.*testRenumberLiveNodes.*bci:9", "= 1"}) + @IR(counts = {"StoreB.*name=b1.*useful1.*bci:4.*testRenumberLiveNodes.*bci:9", "= 1"}) + @IR(counts = {"StoreB.*name=b0.*testRenumberLiveNodes.*bci:13", "= 1"}) + public static void testRenumberLiveNodes() { + // This generates ~3700 useless nodes to trigger RenumberLiveNodes + useless1(42); + + // Do something useful + useful1(); + b0 = 0; + } +} From ebde2fb7d155938e295ecaeb006412f9e49e9d01 Mon Sep 17 00:00:00 2001 From: Christoph Langer Date: Mon, 24 Apr 2023 08:25:27 +0000 Subject: [PATCH 075/217] 8306543: GHA: MSVC installation is failing Backport-of: 5a00617b1be998327825c3abe82ddc213336758d --- .github/workflows/build-windows.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index 86fdba8670f..b6cb8160848 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -96,7 +96,7 @@ jobs: run: | # Run Visual Studio Installer '/c/Program Files (x86)/Microsoft Visual Studio/Installer/vs_installer.exe' \ - modify --quiet --installPath 'C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise' \ + modify --quiet --installPath 'C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise' \ --add Microsoft.VisualStudio.Component.VC.${{ inputs.msvc-toolset-version }}.${{ inputs.msvc-toolset-architecture }} - name: 'Configure' From f969f811a71603f39e4ab42f1362271b7a4d303d Mon Sep 17 00:00:00 2001 From: Goetz Lindenmaier Date: Mon, 24 Apr 2023 09:36:55 +0000 Subject: [PATCH 076/217] 8301998: Update HarfBuzz to 7.0.1 8304295: harfbuzz build fails with GCC 7 after JDK-8301998 Reviewed-by: phh Backport-of: f5c8b68c1c4d8bdbf4838aafdcd657fc104420d8 --- .../java.desktop/lib/Awt2dLibraries.gmk | 5 +- src/java.desktop/share/legal/harfbuzz.md | 47 +- .../Color/CBDT/CBDT.hh} | 85 +- .../Color/COLR/COLR.hh} | 764 +- .../Color/COLR/colrv1-closure.hh} | 11 +- .../Color/CPAL/CPAL.hh} | 14 +- .../Color/sbix/sbix.hh} | 69 +- .../Color/svg/svg.hh} | 33 +- .../libharfbuzz/OT/Layout/Common/Coverage.hh | 337 + .../OT/Layout/Common/CoverageFormat1.hh | 133 + .../OT/Layout/Common/CoverageFormat2.hh | 232 + .../OT/Layout/Common/RangeRecord.hh | 85 + .../native/libharfbuzz/OT/Layout/GDEF/GDEF.hh | 918 ++ .../libharfbuzz/OT/Layout/GPOS/Anchor.hh | 3 +- .../OT/Layout/GPOS/AnchorFormat3.hh | 50 +- .../libharfbuzz/OT/Layout/GPOS/Common.hh | 3 +- .../libharfbuzz/OT/Layout/GPOS/CursivePos.hh | 2 +- .../OT/Layout/GPOS/CursivePosFormat1.hh | 22 +- .../libharfbuzz/OT/Layout/{ => GPOS}/GPOS.hh | 36 +- .../OT/Layout/GPOS/LigatureArray.hh | 56 + .../libharfbuzz/OT/Layout/GPOS/MarkArray.hh | 23 +- .../libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh | 12 +- .../OT/Layout/GPOS/MarkBasePosFormat1.hh | 95 +- .../libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh | 12 +- .../OT/Layout/GPOS/MarkLigPosFormat1.hh | 85 +- .../libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh | 12 +- .../OT/Layout/GPOS/MarkMarkPosFormat1.hh | 15 +- .../libharfbuzz/OT/Layout/GPOS/MarkRecord.hh | 2 +- .../libharfbuzz/OT/Layout/GPOS/PairPos.hh | 16 +- .../OT/Layout/GPOS/PairPosFormat1.hh | 291 +- .../OT/Layout/GPOS/PairPosFormat2.hh | 59 +- .../libharfbuzz/OT/Layout/GPOS/PairSet.hh | 207 + .../OT/Layout/GPOS/PairValueRecord.hh | 99 + .../libharfbuzz/OT/Layout/GPOS/SinglePos.hh | 20 +- .../OT/Layout/GPOS/SinglePosFormat1.hh | 52 +- .../OT/Layout/GPOS/SinglePosFormat2.hh | 44 +- .../libharfbuzz/OT/Layout/GPOS/ValueFormat.hh | 109 +- .../OT/Layout/GSUB/AlternateSet.hh | 22 +- .../OT/Layout/GSUB/AlternateSubst.hh | 19 +- .../OT/Layout/GSUB/AlternateSubstFormat1.hh | 16 +- .../OT/Layout/GSUB/ChainContextSubst.hh | 2 +- .../libharfbuzz/OT/Layout/GSUB/Common.hh | 2 +- .../OT/Layout/GSUB/ContextSubst.hh | 2 +- .../OT/Layout/GSUB/ExtensionSubst.hh | 2 +- .../native/libharfbuzz/OT/Layout/GSUB/GSUB.hh | 19 +- .../libharfbuzz/OT/Layout/GSUB/Ligature.hh | 60 +- .../libharfbuzz/OT/Layout/GSUB/LigatureSet.hh | 15 +- .../OT/Layout/GSUB/LigatureSubst.hh | 20 +- .../OT/Layout/GSUB/LigatureSubstFormat1.hh | 23 +- .../OT/Layout/GSUB/MultipleSubst.hh | 25 +- .../OT/Layout/GSUB/MultipleSubstFormat1.hh | 42 +- .../OT/Layout/GSUB/ReverseChainSingleSubst.hh | 4 +- .../GSUB/ReverseChainSingleSubstFormat1.hh | 40 +- .../libharfbuzz/OT/Layout/GSUB/Sequence.hh | 66 +- .../libharfbuzz/OT/Layout/GSUB/SingleSubst.hh | 42 +- .../OT/Layout/GSUB/SingleSubstFormat1.hh | 88 +- .../OT/Layout/GSUB/SingleSubstFormat2.hh | 49 +- .../libharfbuzz/OT/Layout/GSUB/SubstLookup.hh | 28 +- .../OT/Layout/GSUB/SubstLookupSubTable.hh | 2 +- .../native/libharfbuzz/OT/Layout/types.hh | 66 + .../libharfbuzz/OT/glyf/CompositeGlyph.hh | 215 +- .../share/native/libharfbuzz/OT/glyf/Glyph.hh | 354 +- .../native/libharfbuzz/OT/glyf/GlyphHeader.hh | 16 +- .../native/libharfbuzz/OT/glyf/SimpleGlyph.hh | 131 +- .../native/libharfbuzz/OT/glyf/SubsetGlyph.hh | 23 +- .../libharfbuzz/OT/glyf/VarCompositeGlyph.hh | 354 + .../libharfbuzz/OT/glyf/composite-iter.hh | 68 + .../libharfbuzz/OT/glyf/coord-setter.hh | 34 + .../libharfbuzz/OT/glyf/glyf-helpers.hh | 20 +- .../share/native/libharfbuzz/OT/glyf/glyf.hh | 222 +- .../libharfbuzz/OT/glyf/path-builder.hh | 63 +- .../share/native/libharfbuzz/OT/name/name.hh | 589 ++ .../share/native/libharfbuzz/UPDATING.txt | 125 +- .../libharfbuzz/graph/classdef-graph.hh | 216 + .../libharfbuzz/graph/coverage-graph.hh | 152 + .../share/native/libharfbuzz/graph/graph.hh | 602 +- .../libharfbuzz/graph/gsubgpos-context.cc | 70 + .../libharfbuzz/graph/gsubgpos-context.hh | 61 + .../libharfbuzz/graph/gsubgpos-graph.hh | 414 + .../libharfbuzz/graph/markbasepos-graph.hh | 510 ++ .../native/libharfbuzz/graph/pairpos-graph.hh | 647 ++ .../native/libharfbuzz/graph/serialize.hh | 29 +- .../native/libharfbuzz/graph/split-helpers.hh | 69 + .../libharfbuzz/hb-aat-layout-bsln-table.hh | 4 +- .../libharfbuzz/hb-aat-layout-common.hh | 125 +- .../libharfbuzz/hb-aat-layout-feat-table.hh | 2 +- .../libharfbuzz/hb-aat-layout-just-table.hh | 32 +- .../libharfbuzz/hb-aat-layout-kerx-table.hh | 12 +- .../libharfbuzz/hb-aat-layout-morx-table.hh | 74 +- .../libharfbuzz/hb-aat-layout-opbd-table.hh | 2 +- .../libharfbuzz/hb-aat-layout-trak-table.hh | 8 +- .../share/native/libharfbuzz/hb-aat-layout.cc | 23 +- .../share/native/libharfbuzz/hb-aat-layout.hh | 4 +- .../share/native/libharfbuzz/hb-aat-map.cc | 130 +- .../share/native/libharfbuzz/hb-aat-map.hh | 51 +- .../share/native/libharfbuzz/hb-algs.hh | 158 +- .../share/native/libharfbuzz/hb-array.hh | 113 +- .../share/native/libharfbuzz/hb-atomic.hh | 61 +- .../share/native/libharfbuzz/hb-bit-page.hh | 114 +- .../libharfbuzz/hb-bit-set-invertible.hh | 11 +- .../share/native/libharfbuzz/hb-bit-set.hh | 123 +- .../share/native/libharfbuzz/hb-blob.cc | 22 +- .../share/native/libharfbuzz/hb-blob.h | 2 +- .../share/native/libharfbuzz/hb-blob.hh | 12 +- .../libharfbuzz/hb-buffer-deserialize-json.hh | 455 +- .../hb-buffer-deserialize-text-glyphs.hh | 692 ++ .../hb-buffer-deserialize-text-unicode.hh | 332 + .../libharfbuzz/hb-buffer-deserialize-text.hh | 853 -- .../native/libharfbuzz/hb-buffer-serialize.cc | 49 +- .../native/libharfbuzz/hb-buffer-verify.cc | 9 +- .../share/native/libharfbuzz/hb-buffer.cc | 218 +- .../share/native/libharfbuzz/hb-buffer.h | 33 +- .../share/native/libharfbuzz/hb-buffer.hh | 99 +- .../share/native/libharfbuzz/hb-cache.hh | 33 +- .../libharfbuzz/hb-cff-interp-common.hh | 103 +- .../libharfbuzz/hb-cff-interp-cs-common.hh | 6 + .../libharfbuzz/hb-cff-interp-dict-common.hh | 4 +- .../native/libharfbuzz/hb-cff1-interp-cs.hh | 3 +- .../native/libharfbuzz/hb-cff2-interp-cs.hh | 25 +- .../share/native/libharfbuzz/hb-common.cc | 100 +- .../share/native/libharfbuzz/hb-common.h | 37 + .../share/native/libharfbuzz/hb-config.hh | 21 +- .../share/native/libharfbuzz/hb-cplusplus.hh | 43 +- .../share/native/libharfbuzz/hb-debug.hh | 21 +- .../share/native/libharfbuzz/hb-deprecated.h | 5 +- .../share/native/libharfbuzz/hb-draw.cc | 162 +- .../share/native/libharfbuzz/hb-draw.h | 35 +- .../native/libharfbuzz/hb-face-builder.cc | 246 + .../share/native/libharfbuzz/hb-face.cc | 211 +- .../share/native/libharfbuzz/hb-face.h | 12 +- .../share/native/libharfbuzz/hb-face.hh | 6 +- .../native/libharfbuzz/hb-fallback-shape.cc | 10 - .../share/native/libharfbuzz/hb-font.cc | 527 +- .../share/native/libharfbuzz/hb-font.h | 165 +- .../share/native/libharfbuzz/hb-font.hh | 126 +- .../share/native/libharfbuzz/hb-ft.cc | 454 +- .../share/native/libharfbuzz/hb-iter.hh | 30 +- .../share/native/libharfbuzz/hb-limits.hh | 109 + .../share/native/libharfbuzz/hb-machinery.hh | 53 +- .../share/native/libharfbuzz/hb-map.cc | 102 +- .../share/native/libharfbuzz/hb-map.h | 21 +- .../share/native/libharfbuzz/hb-map.hh | 274 +- .../share/native/libharfbuzz/hb-meta.hh | 15 +- .../share/native/libharfbuzz/hb-multimap.hh | 92 + .../share/native/libharfbuzz/hb-mutex.hh | 12 +- .../share/native/libharfbuzz/hb-null.hh | 31 +- .../native/libharfbuzz/hb-number-parser.hh | 8 +- .../share/native/libharfbuzz/hb-number.cc | 1 - .../share/native/libharfbuzz/hb-object.hh | 73 +- .../share/native/libharfbuzz/hb-open-file.hh | 4 +- .../share/native/libharfbuzz/hb-open-type.hh | 143 +- .../native/libharfbuzz/hb-ot-cff-common.hh | 156 +- .../native/libharfbuzz/hb-ot-cff1-table.cc | 19 +- .../native/libharfbuzz/hb-ot-cff1-table.hh | 18 +- .../native/libharfbuzz/hb-ot-cff2-table.cc | 19 +- .../native/libharfbuzz/hb-ot-cff2-table.hh | 16 +- .../native/libharfbuzz/hb-ot-cmap-table.hh | 265 +- .../share/native/libharfbuzz/hb-ot-color.cc | 67 +- .../share/native/libharfbuzz/hb-ot-color.h | 13 + .../native/libharfbuzz/hb-ot-deprecated.h | 18 +- .../libharfbuzz/hb-ot-face-table-list.hh | 28 +- .../share/native/libharfbuzz/hb-ot-face.cc | 6 +- .../share/native/libharfbuzz/hb-ot-font.cc | 230 +- .../native/libharfbuzz/hb-ot-hdmx-table.hh | 1 + .../native/libharfbuzz/hb-ot-head-table.hh | 4 + .../native/libharfbuzz/hb-ot-hmtx-table.hh | 178 +- .../libharfbuzz/hb-ot-layout-base-table.hh | 2 +- .../native/libharfbuzz/hb-ot-layout-common.hh | 2297 +++-- .../libharfbuzz/hb-ot-layout-gdef-table.hh | 692 +- .../libharfbuzz/hb-ot-layout-gpos-table.hh | 17 +- .../libharfbuzz/hb-ot-layout-gsub-table.hh | 17 +- .../libharfbuzz/hb-ot-layout-gsubgpos.hh | 1371 +-- .../share/native/libharfbuzz/hb-ot-layout.cc | 395 +- .../share/native/libharfbuzz/hb-ot-layout.h | 20 + .../share/native/libharfbuzz/hb-ot-layout.hh | 11 +- .../share/native/libharfbuzz/hb-ot-map.cc | 98 +- .../share/native/libharfbuzz/hb-ot-map.hh | 36 +- .../native/libharfbuzz/hb-ot-math-table.hh | 18 +- .../share/native/libharfbuzz/hb-ot-math.cc | 4 +- .../native/libharfbuzz/hb-ot-maxp-table.hh | 13 + .../native/libharfbuzz/hb-ot-meta-table.hh | 2 +- .../share/native/libharfbuzz/hb-ot-metrics.cc | 12 +- .../native/libharfbuzz/hb-ot-name-table.hh | 376 +- .../share/native/libharfbuzz/hb-ot-name.cc | 51 +- .../share/native/libharfbuzz/hb-ot-name.h | 22 +- .../native/libharfbuzz/hb-ot-os2-table.hh | 123 +- .../libharfbuzz/hb-ot-os2-unicode-ranges.hh | 8 +- .../libharfbuzz/hb-ot-post-table-v2subset.hh | 4 +- .../native/libharfbuzz/hb-ot-post-table.hh | 37 +- .../libharfbuzz/hb-ot-shape-normalize.cc | 2 +- .../share/native/libharfbuzz/hb-ot-shape.cc | 94 +- .../share/native/libharfbuzz/hb-ot-shape.hh | 8 +- .../hb-ot-shaper-arabic-fallback.hh | 29 +- .../hb-ot-shaper-arabic-joining-list.hh | 8 +- .../libharfbuzz/hb-ot-shaper-arabic-table.hh | 8 +- .../native/libharfbuzz/hb-ot-shaper-arabic.cc | 70 +- .../libharfbuzz/hb-ot-shaper-default.cc | 10 +- .../native/libharfbuzz/hb-ot-shaper-hangul.cc | 4 +- .../native/libharfbuzz/hb-ot-shaper-hebrew.cc | 32 +- .../libharfbuzz/hb-ot-shaper-indic-machine.hh | 612 +- .../libharfbuzz/hb-ot-shaper-indic-table.cc | 39 +- .../native/libharfbuzz/hb-ot-shaper-indic.cc | 101 +- .../libharfbuzz/hb-ot-shaper-khmer-machine.hh | 18 +- .../native/libharfbuzz/hb-ot-shaper-khmer.cc | 25 +- .../hb-ot-shaper-myanmar-machine.hh | 18 +- .../libharfbuzz/hb-ot-shaper-myanmar.cc | 56 +- .../libharfbuzz/hb-ot-shaper-syllabic.cc | 12 +- .../libharfbuzz/hb-ot-shaper-syllabic.hh | 4 +- .../native/libharfbuzz/hb-ot-shaper-thai.cc | 10 +- .../libharfbuzz/hb-ot-shaper-use-machine.hh | 1237 +-- .../libharfbuzz/hb-ot-shaper-use-table.hh | 1982 ++--- .../native/libharfbuzz/hb-ot-shaper-use.cc | 39 +- .../hb-ot-shaper-vowel-constraints.cc | 38 +- .../share/native/libharfbuzz/hb-ot-shaper.hh | 22 +- .../native/libharfbuzz/hb-ot-stat-table.hh | 276 +- .../share/native/libharfbuzz/hb-ot-tag.cc | 32 +- .../libharfbuzz/hb-ot-var-avar-table.hh | 85 +- .../native/libharfbuzz/hb-ot-var-common.hh | 84 +- .../libharfbuzz/hb-ot-var-fvar-table.hh | 161 +- .../libharfbuzz/hb-ot-var-gvar-table.hh | 235 +- .../libharfbuzz/hb-ot-var-hvar-table.hh | 31 +- .../libharfbuzz/hb-ot-var-mvar-table.hh | 11 +- .../share/native/libharfbuzz/hb-ot-var.cc | 4 +- .../share/native/libharfbuzz/hb-outline.cc | 322 + .../share/native/libharfbuzz/hb-outline.hh | 83 + .../native/libharfbuzz/hb-paint-extents.cc | 330 + .../native/libharfbuzz/hb-paint-extents.hh | 293 + .../share/native/libharfbuzz/hb-paint.cc | 703 ++ .../share/native/libharfbuzz/hb-paint.h | 987 +++ .../share/native/libharfbuzz/hb-paint.hh | 228 + .../share/native/libharfbuzz/hb-pool.hh | 14 +- .../native/libharfbuzz/hb-priority-queue.hh | 16 +- .../share/native/libharfbuzz/hb-repacker.hh | 255 +- .../share/native/libharfbuzz/hb-sanitize.hh | 23 +- .../share/native/libharfbuzz/hb-serialize.hh | 85 +- .../share/native/libharfbuzz/hb-set-digest.hh | 35 +- .../share/native/libharfbuzz/hb-set.cc | 48 +- .../share/native/libharfbuzz/hb-set.h | 5 +- .../share/native/libharfbuzz/hb-set.hh | 18 +- .../share/native/libharfbuzz/hb-shape-plan.cc | 27 +- .../share/native/libharfbuzz/hb-shape-plan.h | 4 +- .../share/native/libharfbuzz/hb-shape-plan.hh | 3 +- .../share/native/libharfbuzz/hb-shape.cc | 17 +- .../share/native/libharfbuzz/hb-shaper.cc | 4 +- .../share/native/libharfbuzz/hb-static.cc | 48 +- .../libharfbuzz/hb-subset-accelerator.hh | 132 + .../libharfbuzz/hb-subset-cff-common.cc | 11 +- .../libharfbuzz/hb-subset-cff-common.hh | 628 +- .../native/libharfbuzz/hb-subset-cff1.cc | 74 +- .../native/libharfbuzz/hb-subset-cff2.cc | 242 +- .../native/libharfbuzz/hb-subset-input.cc | 288 +- .../native/libharfbuzz/hb-subset-input.hh | 93 +- .../native/libharfbuzz/hb-subset-plan.cc | 871 +- .../native/libharfbuzz/hb-subset-plan.hh | 190 +- .../share/native/libharfbuzz/hb-subset.cc | 179 +- .../share/native/libharfbuzz/hb-subset.h | 39 +- .../share/native/libharfbuzz/hb-subset.hh | 1 + .../share/native/libharfbuzz/hb-ucd-table.hh | 7564 +++++++---------- .../share/native/libharfbuzz/hb-ucd.cc | 16 + .../libharfbuzz/hb-unicode-emoji-table.hh | 71 +- .../share/native/libharfbuzz/hb-unicode.cc | 40 +- .../share/native/libharfbuzz/hb-unicode.h | 8 +- .../share/native/libharfbuzz/hb-utf.hh | 30 +- .../share/native/libharfbuzz/hb-vector.hh | 175 +- .../share/native/libharfbuzz/hb-version.h | 6 +- .../share/native/libharfbuzz/hb.h | 1 + .../share/native/libharfbuzz/hb.hh | 38 +- 267 files changed, 28225 insertions(+), 14923 deletions(-) rename src/java.desktop/share/native/libharfbuzz/{hb-ot-color-cbdt-table.hh => OT/Color/CBDT/CBDT.hh} (93%) rename src/java.desktop/share/native/libharfbuzz/{hb-ot-color-colr-table.hh => OT/Color/COLR/COLR.hh} (68%) rename src/java.desktop/share/native/libharfbuzz/{hb-ot-color-colrv1-closure.hh => OT/Color/COLR/colrv1-closure.hh} (94%) rename src/java.desktop/share/native/libharfbuzz/{hb-ot-color-cpal-table.hh => OT/Color/CPAL/CPAL.hh} (97%) rename src/java.desktop/share/native/libharfbuzz/{hb-ot-color-sbix-table.hh => OT/Color/sbix/sbix.hh} (88%) rename src/java.desktop/share/native/libharfbuzz/{hb-ot-color-svg-table.hh => OT/Color/svg/svg.hh} (83%) create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh rename src/java.desktop/share/native/libharfbuzz/OT/Layout/{ => GPOS}/GPOS.hh (84%) create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/glyf/VarCompositeGlyph.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/glyf/composite-iter.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/glyf/coord-setter.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/OT/name/name.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc create mode 100644 src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh delete mode 100644 src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-limits.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-multimap.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-outline.cc create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-outline.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-paint-extents.cc create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-paint-extents.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-paint.cc create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-paint.h create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-paint.hh create mode 100644 src/java.desktop/share/native/libharfbuzz/hb-subset-accelerator.hh diff --git a/make/modules/java.desktop/lib/Awt2dLibraries.gmk b/make/modules/java.desktop/lib/Awt2dLibraries.gmk index 918a5884851..9fd01cabf0e 100644 --- a/make/modules/java.desktop/lib/Awt2dLibraries.gmk +++ b/make/modules/java.desktop/lib/Awt2dLibraries.gmk @@ -446,7 +446,7 @@ else -DHB_NO_PRAGMA_GCC_DIAGNOSTIC endif ifeq ($(call isTargetOs, linux macosx), true) - HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES + HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES -DHB_NO_VISIBILITY endif # Early re-canonizing has to be disabled to workaround an internal XlC compiler error @@ -459,8 +459,9 @@ else LIBFONTMANAGER_EXCLUDE_FILES += libharfbuzz/hb-ft.cc HARFBUZZ_DISABLED_WARNINGS_gcc := type-limits missing-field-initializers strict-aliasing + # noexcept-type required for GCC 7 builds. Not required for GCC 8+. HARFBUZZ_DISABLED_WARNINGS_CXX_gcc := reorder delete-non-virtual-dtor strict-overflow \ - maybe-uninitialized class-memaccess unused-result extra use-after-free + maybe-uninitialized class-memaccess unused-result extra use-after-free noexcept-type HARFBUZZ_DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \ tautological-constant-out-of-range-compare int-to-pointer-cast \ undef missing-field-initializers range-loop-analysis \ diff --git a/src/java.desktop/share/legal/harfbuzz.md b/src/java.desktop/share/legal/harfbuzz.md index 9037354540b..3426352d51f 100644 --- a/src/java.desktop/share/legal/harfbuzz.md +++ b/src/java.desktop/share/legal/harfbuzz.md @@ -1,8 +1,8 @@ -## Harfbuzz v4.4.1 +## Harfbuzz v7.0.1 ### Harfbuzz License -https://github.com/harfbuzz/harfbuzz/blob/4.4.1/COPYING +https://github.com/harfbuzz/harfbuzz/blob/7.0.1/COPYING
 
@@ -12,21 +12,22 @@ files names COPYING in subdirectories where applicable.
 
 Copyright © 2010-2022  Google, Inc.
 Copyright © 2018-2020  Ebrahim Byagowi
-Copyright © 2019-2020  Facebook, Inc.
-Copyright © 2012-2015  Mozilla Foundation.
-Copyright © 2011  Codethink Limited
-Copyright © 2008-2010  Nokia Corporation and/or its subsidiary(-ies)
-Copyright © 2009  Keith Stribley
-Copyright © 2009  Martin Hosken and SIL International
-Copyright © 2007  Chris Wilson
-Copyright © 2005-2022 Behdad Esfahbod
-Copyright © 2005  David Turner
 Copyright © 2004-2013  Red Hat, Inc.
-Copyright © 1998-2004  David Turner and Werner Lemberg
-Copyright © 2016  Elie Roux 
+Copyright © 2019  Facebook, Inc.
+Copyright © 2007  Chris Wilson
 Copyright © 2018-2019 Adobe Inc.
+Copyright © 2006-2023 Behdad Esfahbod
+Copyright © 1998-2004  David Turner and Werner Lemberg
+Copyright © 2009  Keith Stribley
 Copyright © 2018  Khaled Hosny
+Copyright © 2016  Elie Roux 
 Copyright © 2016  Igalia S.L.
+Copyright © 2015  Mozilla Foundation.
+Copyright © 1999  David Turner
+Copyright © 2005  Werner Lemberg
+Copyright © 2013-2015  Alexei Podtelezhnikov
+Copyright © 2022 Matthias Clasen
+Copyright © 2011  Codethink Limited
 
 For full copyright notices consult the individual files in the package.
 
@@ -72,3 +73,23 @@ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 
 
+ +### AUTHORS File Information +``` + +Behdad Esfahbod +David Corbett +David Turner +Ebrahim Byagowi +Garret Rieger +Jonathan Kew +Khaled Hosny +Lars Knoll +Martin Hosken +Owen Taylor +Roderick Sheeter +Roozbeh Pournader +Simon Hausmann +Werner Lemberg + +``` diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh similarity index 93% rename from src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh rename to src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh index 70d78c74d3b..11aeda5297f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cbdt-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/CBDT/CBDT.hh @@ -24,10 +24,11 @@ * Google Author(s): Seigo Nonaka, Calder Kitagawa */ -#ifndef HB_OT_COLOR_CBDT_TABLE_HH -#define HB_OT_COLOR_CBDT_TABLE_HH +#ifndef OT_COLOR_CBDT_CBDT_HH +#define OT_COLOR_CBDT_CBDT_HH -#include "hb-open-type.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-paint.hh" /* * CBLC -- Color Bitmap Location @@ -67,7 +68,7 @@ _copy_data_to_cbdt (hb_vector_t *cbdt_prime, { unsigned int new_len = cbdt_prime->length + length; if (unlikely (!cbdt_prime->alloc (new_len))) return false; - memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length); + hb_memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length); cbdt_prime->length = new_len; return true; } @@ -80,12 +81,15 @@ struct SmallGlyphMetrics return_trace (c->check_struct (this)); } - void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scale) const { - extents->x_bearing = font->em_scale_x (bearingX); - extents->y_bearing = font->em_scale_y (bearingY); - extents->width = font->em_scale_x (width); - extents->height = font->em_scale_y (-static_cast(height)); + extents->x_bearing = bearingX; + extents->y_bearing = bearingY; + extents->width = width; + extents->height = -static_cast (height); + + if (scale) + font->scale_glyph_extents (extents); } HBUINT8 height; @@ -307,7 +311,7 @@ struct IndexSubtable } } - bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const + bool get_extents (hb_glyph_extents_t *extents HB_UNUSED, bool scale HB_UNUSED) const { switch (u.header.indexFormat) { @@ -468,13 +472,13 @@ struct IndexSubtableRecord if (unlikely (!c->serializer->check_success (records->resize (records->length + 1)))) return_trace (false); - (*records)[records->length - 1].firstGlyphIndex = 1; - (*records)[records->length - 1].lastGlyphIndex = 0; + records->tail ().firstGlyphIndex = 1; + records->tail ().lastGlyphIndex = 0; bitmap_size_context->size += IndexSubtableRecord::min_size; c->serializer->push (); - if (unlikely (!add_new_subtable (c, bitmap_size_context, &((*records)[records->length - 1]), lookup, base, start))) + if (unlikely (!add_new_subtable (c, bitmap_size_context, &(records->tail ()), lookup, base, start))) { c->serializer->pop_discard (); c->serializer->revert (snap); @@ -504,8 +508,8 @@ struct IndexSubtableRecord return num_missing; } - bool get_extents (hb_glyph_extents_t *extents, const void *base) const - { return (base+offsetToSubtable).get_extents (extents); } + bool get_extents (hb_glyph_extents_t *extents, const void *base, bool scale) const + { return (base+offsetToSubtable).get_extents (extents, scale); } bool get_image_data (unsigned int gid, const void *base, @@ -833,7 +837,7 @@ struct CBDT } bool - get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, bool scale = true) const { const void *base; const BitmapSizeTable &strike = this->cblc->choose_strike (font); @@ -841,7 +845,7 @@ struct CBDT if (!subtable_record || !strike.ppemX || !strike.ppemY) return false; - if (subtable_record->get_extents (extents, base)) + if (subtable_record->get_extents (extents, base, scale)) return true; unsigned int image_offset = 0, image_length = 0, image_format = 0; @@ -858,26 +862,29 @@ struct CBDT if (unlikely (image_length < GlyphBitmapDataFormat17::min_size)) return false; auto &glyphFormat17 = StructAtOffset (this->cbdt, image_offset); - glyphFormat17.glyphMetrics.get_extents (font, extents); + glyphFormat17.glyphMetrics.get_extents (font, extents, scale); break; } case 18: { if (unlikely (image_length < GlyphBitmapDataFormat18::min_size)) return false; auto &glyphFormat18 = StructAtOffset (this->cbdt, image_offset); - glyphFormat18.glyphMetrics.get_extents (font, extents); + glyphFormat18.glyphMetrics.get_extents (font, extents, scale); break; } default: return false; /* TODO: Support other image formats. */ } /* Convert to font units. */ - float x_scale = upem / (float) strike.ppemX; - float y_scale = upem / (float) strike.ppemY; - extents->x_bearing = roundf (extents->x_bearing * x_scale); - extents->y_bearing = roundf (extents->y_bearing * y_scale); - extents->width = roundf (extents->width * x_scale); - extents->height = roundf (extents->height * y_scale); + if (scale) + { + float x_scale = upem / (float) strike.ppemX; + float y_scale = upem / (float) strike.ppemY; + extents->x_bearing = roundf (extents->x_bearing * x_scale); + extents->y_bearing = roundf (extents->y_bearing * y_scale); + extents->width = roundf (extents->width * x_scale); + extents->height = roundf (extents->height * y_scale); + } return true; } @@ -934,6 +941,32 @@ struct CBDT bool has_data () const { return cbdt.get_length (); } + bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const + { + hb_glyph_extents_t extents; + hb_glyph_extents_t pixel_extents; + hb_blob_t *blob = reference_png (font, glyph); + + if (unlikely (blob == hb_blob_get_empty ())) + return false; + + if (unlikely (!hb_font_get_glyph_extents (font, glyph, &extents))) + return false; + + if (unlikely (!get_extents (font, glyph, &pixel_extents, false))) + return false; + + bool ret = funcs->image (data, + blob, + pixel_extents.width, -pixel_extents.height, + HB_PAINT_IMAGE_FORMAT_PNG, + font->slant_xy, + &extents); + + hb_blob_destroy (blob); + return ret; + } + private: hb_blob_ptr_t cblc; hb_blob_ptr_t cbdt; @@ -994,4 +1027,4 @@ struct CBDT_accelerator_t : CBDT::accelerator_t { } /* namespace OT */ -#endif /* HB_OT_COLOR_CBDT_TABLE_HH */ +#endif /* OT_COLOR_CBDT_CBDT_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh similarity index 68% rename from src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh rename to src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh index 6b9e734615b..c286ee3c908 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colr-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/COLR.hh @@ -25,12 +25,14 @@ * Google Author(s): Calder Kitagawa */ -#ifndef HB_OT_COLOR_COLR_TABLE_HH -#define HB_OT_COLOR_COLR_TABLE_HH +#ifndef OT_COLOR_COLR_COLR_HH +#define OT_COLOR_COLR_COLR_HH -#include "hb-open-type.hh" -#include "hb-ot-layout-common.hh" -#include "hb-ot-var-common.hh" +#include "../../../hb.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-ot-var-common.hh" +#include "../../../hb-paint.hh" +#include "../../../hb-paint-extents.hh" /* * COLR -- Color @@ -38,17 +40,82 @@ */ #define HB_OT_TAG_COLR HB_TAG('C','O','L','R') -#ifndef HB_COLRV1_MAX_NESTING_LEVEL -#define HB_COLRV1_MAX_NESTING_LEVEL 100 -#endif -#ifndef COLRV1_ENABLE_SUBSETTING -#define COLRV1_ENABLE_SUBSETTING 1 -#endif +namespace OT { +struct hb_paint_context_t; +} namespace OT { struct COLR; + +struct Paint; + +struct hb_paint_context_t : + hb_dispatch_context_t +{ + template + return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); } + static return_t default_return_value () { return hb_empty_t (); } + + const COLR* get_colr_table () const + { return reinterpret_cast (base); } + +public: + const void *base; + hb_paint_funcs_t *funcs; + void *data; + hb_font_t *font; + unsigned int palette_index; + hb_color_t foreground; + VarStoreInstancer &instancer; + int depth_left = HB_MAX_NESTING_LEVEL; + int edge_count = HB_COLRV1_MAX_EDGE_COUNT; + + hb_paint_context_t (const void *base_, + hb_paint_funcs_t *funcs_, + void *data_, + hb_font_t *font_, + unsigned int palette_, + hb_color_t foreground_, + VarStoreInstancer &instancer_) : + base (base_), + funcs (funcs_), + data (data_), + font (font_), + palette_index (palette_), + foreground (foreground_), + instancer (instancer_) + { } + + hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground) + { + hb_color_t color = foreground; + + *is_foreground = true; + + if (color_index != 0xffff) + { + if (!funcs->custom_palette_color (data, color_index, &color)) + { + unsigned int clen = 1; + hb_face_t *face = hb_font_get_face (font); + + hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color); + } + + *is_foreground = false; + } + + return HB_COLOR (hb_color_get_blue (color), + hb_color_get_green (color), + hb_color_get_red (color), + hb_color_get_alpha (color) * alpha); + } + + inline void recurse (const Paint &paint); +}; + struct hb_colrv1_closure_context_t : hb_dispatch_context_t { @@ -102,7 +169,7 @@ struct hb_colrv1_closure_context_t : hb_set_t *glyphs_, hb_set_t *layer_indices_, hb_set_t *palette_indices_, - unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) : + unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) : base (base_), glyphs (glyphs_), layer_indices (layer_indices_), @@ -145,7 +212,7 @@ struct BaseGlyphRecord bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } public: @@ -164,6 +231,8 @@ struct BaseGlyphRecord template struct Variable { + static constexpr bool is_variable = true; + Variable* copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); @@ -186,8 +255,26 @@ struct Variable return_trace (c->check_struct (this) && value.sanitize (c)); } + void paint_glyph (hb_paint_context_t *c) const + { + value.paint_glyph (c, varIdxBase); + } + + void get_color_stop (hb_paint_context_t *c, + hb_color_stop_t *stop, + const VarStoreInstancer &instancer) const + { + value.get_color_stop (c, stop, varIdxBase, instancer); + } + + hb_paint_extend_t get_extend () const + { + return value.get_extend (); + } + protected: T value; + public: VarIdx varIdxBase; public: DEFINE_SIZE_STATIC (4 + T::static_size); @@ -196,6 +283,10 @@ struct Variable template struct NoVariable { + static constexpr bool is_variable = false; + + static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION; + NoVariable* copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); @@ -217,6 +308,23 @@ struct NoVariable return_trace (c->check_struct (this) && value.sanitize (c)); } + void paint_glyph (hb_paint_context_t *c) const + { + value.paint_glyph (c, varIdxBase); + } + + void get_color_stop (hb_paint_context_t *c, + hb_color_stop_t *stop, + const VarStoreInstancer &instancer) const + { + value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer); + } + + hb_paint_extend_t get_extend () const + { + return value.get_extend (); + } + T value; public: DEFINE_SIZE_STATIC (T::static_size); @@ -234,7 +342,7 @@ struct ColorStop TRACE_SUBSET (this); auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), + return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -244,6 +352,17 @@ struct ColorStop return_trace (c->check_struct (this)); } + void get_color_stop (hb_paint_context_t *c, + hb_color_stop_t *out, + uint32_t varIdx, + const VarStoreInstancer &instancer) const + { + out->offset = stopOffset.to_float(instancer (varIdx, 0)); + out->color = c->get_color (paletteIndex, + alpha.to_float (instancer (varIdx, 1)), + &out->is_foreground); + } + F2DOT14 stopOffset; HBUINT16 paletteIndex; F2DOT14 alpha; @@ -295,6 +414,52 @@ struct ColorLine stops.sanitize (c)); } + /* get up to count stops from start */ + unsigned int + get_color_stops (hb_paint_context_t *c, + unsigned int start, + unsigned int *count, + hb_color_stop_t *color_stops, + const VarStoreInstancer &instancer) const + { + unsigned int len = stops.len; + + if (count && color_stops) + { + unsigned int i; + for (i = 0; i < *count && start + i < len; i++) + stops[start + i].get_color_stop (c, &color_stops[i], instancer); + *count = i; + } + + return len; + } + + HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line, + void *color_line_data, + unsigned int start, + unsigned int *count, + hb_color_stop_t *color_stops, + void *user_data) + { + const ColorLine *thiz = (const ColorLine *) color_line_data; + hb_paint_context_t *c = (hb_paint_context_t *) user_data; + return thiz->get_color_stops (c, start, count, color_stops, c->instancer); + } + + hb_paint_extend_t get_extend () const + { + return (hb_paint_extend_t) (unsigned int) extend; + } + + HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line, + void *color_line_data, + void *user_data) + { + const ColorLine *thiz = (const ColorLine *) color_line_data; + return thiz->get_extend (); + } + Extend extend; Array16Of> stops; public: @@ -358,14 +523,25 @@ struct Affine2x3 return_trace (c->check_struct (this)); } - HBFixed xx; - HBFixed yx; - HBFixed xy; - HBFixed yy; - HBFixed dx; - HBFixed dy; + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + c->funcs->push_transform (c->data, + xx.to_float (c->instancer (varIdxBase, 0)), + yx.to_float (c->instancer (varIdxBase, 1)), + xy.to_float (c->instancer (varIdxBase, 2)), + yy.to_float (c->instancer (varIdxBase, 3)), + dx.to_float (c->instancer (varIdxBase, 4)), + dy.to_float (c->instancer (varIdxBase, 5))); + } + + F16DOT16 xx; + F16DOT16 yx; + F16DOT16 xy; + F16DOT16 yy; + F16DOT16 dx; + F16DOT16 dy; public: - DEFINE_SIZE_STATIC (6 * HBFixed::static_size); + DEFINE_SIZE_STATIC (6 * F16DOT16::static_size); }; struct PaintColrLayers @@ -377,7 +553,7 @@ struct PaintColrLayers TRACE_SUBSET (this); auto *out = c->serializer->embed (this); if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex), + return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW)); return_trace (true); @@ -389,6 +565,8 @@ struct PaintColrLayers return_trace (c->check_struct (this)); } + inline void paint_glyph (hb_paint_context_t *c) const; + HBUINT8 format; /* format = 1 */ HBUINT8 numLayers; HBUINT32 firstLayerIndex; /* index into COLRv1::layerList */ @@ -406,7 +584,7 @@ struct PaintSolid TRACE_SUBSET (this); auto *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); - return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex), + return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW)); } @@ -416,6 +594,17 @@ struct PaintSolid return_trace (c->check_struct (this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + hb_bool_t is_foreground; + hb_color_t color; + + color = c->get_color (paletteIndex, + alpha.to_float (c->instancer (varIdxBase, 0)), + &is_foreground); + c->funcs->color (c->data, is_foreground, color); + } + HBUINT8 format; /* format = 2(noVar) or 3(Var)*/ HBUINT16 paletteIndex; F2DOT14 alpha; @@ -444,6 +633,23 @@ struct PaintLinearGradient return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + hb_color_line_t cl = { + (void *) &(this+colorLine), + (this+colorLine).static_get_color_stops, c, + (this+colorLine).static_get_extend, nullptr + }; + + c->funcs->linear_gradient (c->data, &cl, + x0 + c->instancer (varIdxBase, 0), + y0 + c->instancer (varIdxBase, 1), + x1 + c->instancer (varIdxBase, 2), + y1 + c->instancer (varIdxBase, 3), + x2 + c->instancer (varIdxBase, 4), + y2 + c->instancer (varIdxBase, 5)); + } + HBUINT8 format; /* format = 4(noVar) or 5 (Var) */ Offset24To> colorLine; /* Offset (from beginning of PaintLinearGradient * table) to ColorLine subtable. */ @@ -478,6 +684,23 @@ struct PaintRadialGradient return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + hb_color_line_t cl = { + (void *) &(this+colorLine), + (this+colorLine).static_get_color_stops, c, + (this+colorLine).static_get_extend, nullptr + }; + + c->funcs->radial_gradient (c->data, &cl, + x0 + c->instancer (varIdxBase, 0), + y0 + c->instancer (varIdxBase, 1), + radius0 + c->instancer (varIdxBase, 2), + x1 + c->instancer (varIdxBase, 3), + y1 + c->instancer (varIdxBase, 4), + radius1 + c->instancer (varIdxBase, 5)); + } + HBUINT8 format; /* format = 6(noVar) or 7 (Var) */ Offset24To> colorLine; /* Offset (from beginning of PaintRadialGradient * table) to ColorLine subtable. */ @@ -512,6 +735,21 @@ struct PaintSweepGradient return_trace (c->check_struct (this) && colorLine.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + hb_color_line_t cl = { + (void *) &(this+colorLine), + (this+colorLine).static_get_color_stops, c, + (this+colorLine).static_get_extend, nullptr + }; + + c->funcs->sweep_gradient (c->data, &cl, + centerX + c->instancer (varIdxBase, 0), + centerY + c->instancer (varIdxBase, 1), + (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * (float) M_PI, + (endAngle.to_float (c->instancer (varIdxBase, 3)) + 1) * (float) M_PI); + } + HBUINT8 format; /* format = 8(noVar) or 9 (Var) */ Offset24To> colorLine; /* Offset (from beginning of PaintSweepGradient * table) to ColorLine subtable. */ @@ -523,7 +761,6 @@ struct PaintSweepGradient DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size); }; -struct Paint; // Paint a non-COLR glyph, filled as indicated by paint. struct PaintGlyph { @@ -548,6 +785,17 @@ struct PaintGlyph return_trace (c->check_struct (this) && paint.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c) const + { + c->funcs->push_inverse_root_transform (c->data, c->font); + c->funcs->push_clip_glyph (c->data, gid, c->font); + c->funcs->push_root_transform (c->data, c->font); + c->recurse (this+paint); + c->funcs->pop_transform (c->data); + c->funcs->pop_clip (c->data); + c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 10 */ Offset24To paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */ HBUINT16 gid; @@ -575,6 +823,8 @@ struct PaintColrGlyph return_trace (c->check_struct (this)); } + inline void paint_glyph (hb_paint_context_t *c) const; + HBUINT8 format; /* format = 11 */ HBUINT16 gid; public: @@ -603,6 +853,13 @@ struct PaintTransform transform.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c) const + { + (this+transform).paint_glyph (c); + c->recurse (this+src); + c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 12(noVar) or 13 (Var) */ Offset24To src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */ Offset24To> transform; @@ -629,6 +886,16 @@ struct PaintTranslate return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float ddx = dx + c->instancer (varIdxBase, 0); + float ddy = dy + c->instancer (varIdxBase, 1); + + bool p1 = c->funcs->push_translate (c->data, ddx, ddy); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 14(noVar) or 15 (Var) */ Offset24To src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */ FWORD dx; @@ -656,6 +923,16 @@ struct PaintScale return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float sx = scaleX.to_float (c->instancer (varIdxBase, 0)); + float sy = scaleY.to_float (c->instancer (varIdxBase, 1)); + + bool p1 = c->funcs->push_scale (c->data, sx, sy); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 16 (noVar) or 17(Var) */ Offset24To src; /* Offset (from beginning of PaintScale table) to Paint subtable. */ F2DOT14 scaleX; @@ -683,6 +960,22 @@ struct PaintScaleAroundCenter return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float sx = scaleX.to_float (c->instancer (varIdxBase, 0)); + float sy = scaleY.to_float (c->instancer (varIdxBase, 1)); + float tCenterX = centerX + c->instancer (varIdxBase, 2); + float tCenterY = centerY + c->instancer (varIdxBase, 3); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_scale (c->data, sx, sy); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 18 (noVar) or 19(Var) */ Offset24To src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */ F2DOT14 scaleX; @@ -712,6 +1005,15 @@ struct PaintScaleUniform return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float s = scale.to_float (c->instancer (varIdxBase, 0)); + + bool p1 = c->funcs->push_scale (c->data, s, s); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 20 (noVar) or 21(Var) */ Offset24To src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */ F2DOT14 scale; @@ -738,6 +1040,21 @@ struct PaintScaleUniformAroundCenter return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float s = scale.to_float (c->instancer (varIdxBase, 0)); + float tCenterX = centerX + c->instancer (varIdxBase, 1); + float tCenterY = centerY + c->instancer (varIdxBase, 2); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_scale (c->data, s, s); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 22 (noVar) or 23(Var) */ Offset24To src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */ F2DOT14 scale; @@ -766,6 +1083,15 @@ struct PaintRotate return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float a = angle.to_float (c->instancer (varIdxBase, 0)); + + bool p1 = c->funcs->push_rotate (c->data, a); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 24 (noVar) or 25(Var) */ Offset24To src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */ F2DOT14 angle; @@ -792,6 +1118,21 @@ struct PaintRotateAroundCenter return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float a = angle.to_float (c->instancer (varIdxBase, 0)); + float tCenterX = centerX + c->instancer (varIdxBase, 1); + float tCenterY = centerY + c->instancer (varIdxBase, 2); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_rotate (c->data, a); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 26 (noVar) or 27(Var) */ Offset24To src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */ F2DOT14 angle; @@ -820,6 +1161,16 @@ struct PaintSkew return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0)); + float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1)); + + bool p1 = c->funcs->push_skew (c->data, sx, sy); + c->recurse (this+src); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 28(noVar) or 29 (Var) */ Offset24To src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */ F2DOT14 xSkewAngle; @@ -847,6 +1198,22 @@ struct PaintSkewAroundCenter return_trace (c->check_struct (this) && src.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const + { + float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0)); + float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1)); + float tCenterX = centerX + c->instancer (varIdxBase, 2); + float tCenterY = centerY + c->instancer (varIdxBase, 3); + + bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY); + bool p2 = c->funcs->push_skew (c->data, sx, sy); + bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY); + c->recurse (this+src); + if (p3) c->funcs->pop_transform (c->data); + if (p2) c->funcs->pop_transform (c->data); + if (p1) c->funcs->pop_transform (c->data); + } + HBUINT8 format; /* format = 30(noVar) or 31 (Var) */ Offset24To src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */ F2DOT14 xSkewAngle; @@ -879,6 +1246,14 @@ struct PaintComposite backdrop.sanitize (c, this)); } + void paint_glyph (hb_paint_context_t *c) const + { + c->recurse (this+backdrop); + c->funcs->push_group (c->data); + c->recurse (this+src); + c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode); + } + HBUINT8 format; /* format = 32 */ Offset24To src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */ CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */ @@ -887,6 +1262,11 @@ struct PaintComposite DEFINE_SIZE_STATIC (8); }; +struct ClipBoxData +{ + int xMin, yMin, xMax, yMax; +}; + struct ClipBoxFormat1 { bool sanitize (hb_sanitize_context_t *c) const @@ -895,6 +1275,14 @@ struct ClipBoxFormat1 return_trace (c->check_struct (this)); } + void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer HB_UNUSED) const + { + clip_box.xMin = xMin; + clip_box.yMin = yMin; + clip_box.xMax = xMax; + clip_box.yMax = yMax; + } + public: HBUINT8 format; /* format = 1(noVar) or 2(Var)*/ FWORD xMin; @@ -905,7 +1293,20 @@ struct ClipBoxFormat1 DEFINE_SIZE_STATIC (1 + 4 * FWORD::static_size); }; -struct ClipBoxFormat2 : Variable {}; +struct ClipBoxFormat2 : Variable +{ + void get_clip_box (ClipBoxData &clip_box, const VarStoreInstancer &instancer) const + { + value.get_clip_box(clip_box, instancer); + if (instancer) + { + clip_box.xMin += _hb_roundf (instancer (varIdxBase, 0)); + clip_box.yMin += _hb_roundf (instancer (varIdxBase, 1)); + clip_box.xMax += _hb_roundf (instancer (varIdxBase, 2)); + clip_box.yMax += _hb_roundf (instancer (varIdxBase, 3)); + } + } +}; struct ClipBox { @@ -922,8 +1323,8 @@ struct ClipBox template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); @@ -931,6 +1332,28 @@ struct ClipBox } } + bool get_extents (hb_glyph_extents_t *extents, + const VarStoreInstancer &instancer) const + { + ClipBoxData clip_box; + switch (u.format) { + case 1: + u.format1.get_clip_box (clip_box, instancer); + break; + case 2: + u.format2.get_clip_box (clip_box, instancer); + break; + default: + return false; + } + + extents->x_bearing = clip_box.xMin; + extents->y_bearing = clip_box.yMax; + extents->width = clip_box.xMax - clip_box.xMin; + extents->height = clip_box.yMin - clip_box.yMax; + return true; + } + protected: union { HBUINT8 format; /* Format identifier */ @@ -941,6 +1364,9 @@ struct ClipBox struct ClipRecord { + int cmp (hb_codepoint_t g) const + { return g < startGlyphID ? -1 : g <= endGlyphID ? 0 : +1; } + ClipRecord* copy (hb_serialize_context_t *c, const void *base) const { TRACE_SERIALIZE (this); @@ -956,6 +1382,13 @@ struct ClipRecord return_trace (c->check_struct (this) && clipBox.sanitize (c, base)); } + bool get_extents (hb_glyph_extents_t *extents, + const void *base, + const VarStoreInstancer &instancer) const + { + return (base+clipBox).get_extents (extents, instancer); + } + public: HBUINT16 startGlyphID; // first gid clip applies to HBUINT16 endGlyphID; // last gid clip applies to, inclusive @@ -963,6 +1396,7 @@ struct ClipRecord public: DEFINE_SIZE_STATIC (7); }; +DECLARE_NULL_NAMESPACE_BYTES (OT, ClipRecord); struct ClipList { @@ -1025,7 +1459,7 @@ struct ClipList if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - const hb_set_t& glyphset = *c->plan->_glyphset_colred; + const hb_set_t& glyphset = c->plan->_glyphset_colred; const hb_map_t &glyph_map = *c->plan->glyph_map; hb_map_t new_gid_offset_map; @@ -1051,11 +1485,26 @@ struct ClipList bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); + // TODO Make a formatted struct! return_trace (c->check_struct (this) && clips.sanitize (c, this)); } + bool + get_extents (hb_codepoint_t gid, + hb_glyph_extents_t *extents, + const VarStoreInstancer &instancer) const + { + auto *rec = clips.as_array ().bsearch (gid); + if (rec) + { + rec->get_extents (extents, this, instancer); + return true; + } + return false; + } + HBUINT8 format; // Set to 1. - Array32Of clips; // Clip records, sorted by startGlyphID + SortedArray32Of clips; // Clip records, sorted by startGlyphID public: DEFINE_SIZE_ARRAY_SIZED (5, clips); }; @@ -1068,7 +1517,7 @@ struct Paint { TRACE_SANITIZE (this); - if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL))) + if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL))) return_trace (c->no_dispatch_return_value ()); return_trace (c->end_recursion (this->dispatch (c, std::forward (ds)...))); @@ -1077,8 +1526,8 @@ struct Paint template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.paintformat1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.paintformat2, std::forward (ds)...)); @@ -1120,38 +1569,40 @@ struct Paint union { HBUINT8 format; PaintColrLayers paintformat1; - PaintSolid paintformat2; + NoVariable paintformat2; Variable paintformat3; - PaintLinearGradient paintformat4; + NoVariable> paintformat4; Variable> paintformat5; - PaintRadialGradient paintformat6; + NoVariable> paintformat6; Variable> paintformat7; - PaintSweepGradient paintformat8; + NoVariable> paintformat8; Variable> paintformat9; PaintGlyph paintformat10; PaintColrGlyph paintformat11; PaintTransform paintformat12; PaintTransform paintformat13; - PaintTranslate paintformat14; + NoVariable paintformat14; Variable paintformat15; - PaintScale paintformat16; + NoVariable paintformat16; Variable paintformat17; - PaintScaleAroundCenter paintformat18; + NoVariable paintformat18; Variable paintformat19; - PaintScaleUniform paintformat20; + NoVariable paintformat20; Variable paintformat21; - PaintScaleUniformAroundCenter paintformat22; + NoVariable paintformat22; Variable paintformat23; - PaintRotate paintformat24; + NoVariable paintformat24; Variable paintformat25; - PaintRotateAroundCenter paintformat26; + NoVariable paintformat26; Variable paintformat27; - PaintSkew paintformat28; + NoVariable paintformat28; Variable paintformat29; - PaintSkewAroundCenter paintformat30; + NoVariable paintformat30; Variable paintformat31; PaintComposite paintformat32; } u; + public: + DEFINE_SIZE_MIN (2); }; struct BaseGlyphPaintRecord @@ -1193,7 +1644,7 @@ struct BaseGlyphList : SortedArray32Of TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - const hb_set_t* glyphset = c->plan->_glyphset_colred; + const hb_set_t* glyphset = &c->plan->_glyphset_colred; for (const auto& _ : as_array ()) { @@ -1247,7 +1698,14 @@ struct COLR { static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR; - bool has_data () const { return numBaseGlyphs; } + bool has_v0_data () const { return numBaseGlyphs; } + bool has_v1_data () const + { + if (version == 1) + return (this+baseGlyphList).len > 0; + + return false; + } unsigned int get_glyph_layers (hb_codepoint_t glyph, unsigned int start_offset, @@ -1356,7 +1814,7 @@ struct COLR (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) && (this+layersZ).sanitize (c, numLayers) && (version == 0 || - (COLRV1_ENABLE_SUBSETTING && version == 1 && + (version == 1 && baseGlyphList.sanitize (c, this) && layerList.sanitize (c, this) && clipList.sanitize (c, this) && @@ -1427,7 +1885,7 @@ struct COLR TRACE_SUBSET (this); const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; - const hb_set_t& glyphset = *c->plan->_glyphset_colred; + const hb_set_t& glyphset = c->plan->_glyphset_colred; auto base_it = + hb_range (c->plan->num_output_glyphs ()) @@ -1476,7 +1934,7 @@ struct COLR if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid))) return hb_pair_t> (false, out_layers); out_layers[i].glyphId = new_gid; - out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx); + out_layers[i].colorIdx = c->plan->colr_palettes.get (layers[i].colorIdx); } return hb_pair_t> (true, out_layers); @@ -1509,10 +1967,171 @@ struct COLR colr_prime->layerList.serialize_subset (c, layerList, this); colr_prime->clipList.serialize_subset (c, clipList, this); colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this); - //TODO: subset varStore once it's implemented in fonttools + colr_prime->varStore.serialize_copy (c->serializer, varStore, this); return_trace (true); } + const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const + { + const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList; + const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph); + if (record) + { + const Paint &paint = &baseglyph_paintrecords+record->paint; + return &paint; + } + else + return nullptr; + } + + bool + get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + { + if (version != 1) + return false; + + VarStoreInstancer instancer (this+varStore, + this+varIdxMap, + hb_array (font->coords, font->num_coords)); + + if (get_clip (glyph, extents, instancer)) + { + font->scale_glyph_extents (extents); + return true; + } + + auto *extents_funcs = hb_paint_extents_get_funcs (); + hb_paint_extents_context_t extents_data; + bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0)); + + hb_extents_t e = extents_data.get_extents (); + if (e.is_void ()) + { + extents->x_bearing = 0; + extents->y_bearing = 0; + extents->width = 0; + extents->height = 0; + } + else + { + extents->x_bearing = e.xmin; + extents->y_bearing = e.ymax; + extents->width = e.xmax - e.xmin; + extents->height = e.ymin - e.ymax; + } + + return ret; + } + + bool + has_paint_for_glyph (hb_codepoint_t glyph) const + { + if (version == 1) + { + const Paint *paint = get_base_glyph_paint (glyph); + + return paint != nullptr; + } + + return false; + } + + bool get_clip (hb_codepoint_t glyph, + hb_glyph_extents_t *extents, + const VarStoreInstancer instancer) const + { + return (this+clipList).get_extents (glyph, + extents, + instancer); + } + + bool + paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const + { + VarStoreInstancer instancer (this+varStore, + this+varIdxMap, + hb_array (font->coords, font->num_coords)); + hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer); + + if (version == 1) + { + const Paint *paint = get_base_glyph_paint (glyph); + if (paint) + { + // COLRv1 glyph + + VarStoreInstancer instancer (this+varStore, + this+varIdxMap, + hb_array (font->coords, font->num_coords)); + + bool is_bounded = true; + if (clip) + { + hb_glyph_extents_t extents; + if (get_clip (glyph, &extents, instancer)) + { + font->scale_glyph_extents (&extents); + c.funcs->push_clip_rectangle (c.data, + extents.x_bearing, + extents.y_bearing + extents.height, + extents.x_bearing + extents.width, + extents.y_bearing); + } + else + { + auto *extents_funcs = hb_paint_extents_get_funcs (); + hb_paint_extents_context_t extents_data; + + paint_glyph (font, glyph, + extents_funcs, &extents_data, + palette_index, foreground, + false); + + hb_extents_t extents = extents_data.get_extents (); + is_bounded = extents_data.is_bounded (); + + c.funcs->push_clip_rectangle (c.data, + extents.xmin, + extents.ymin, + extents.xmax, + extents.ymax); + } + } + + c.funcs->push_root_transform (c.data, font); + + if (is_bounded) + c.recurse (*paint); + + c.funcs->pop_transform (c.data); + + if (clip) + c.funcs->pop_clip (c.data); + + return true; + } + } + + const BaseGlyphRecord *record = get_base_glyph_record (glyph); + if (record && ((hb_codepoint_t) record->glyphId == glyph)) + { + // COLRv0 glyph + for (const auto &r : (this+layersZ).as_array (numLayers) + .sub_array (record->firstLayerIdx, record->numLayers)) + { + hb_bool_t is_foreground; + hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground); + c.funcs->push_clip_glyph (c.data, r.glyphId, c.font); + c.funcs->color (c.data, is_foreground, color); + c.funcs->pop_clip (c.data); + } + + return true; + } + + return false; + } + protected: HBUINT16 version; /* Table version number (starts at 0). */ HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */ @@ -1535,7 +2154,50 @@ struct COLR_accelerator_t : COLR::accelerator_t { COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {} }; -} /* namespace OT */ +void +hb_paint_context_t::recurse (const Paint &paint) +{ + if (unlikely (depth_left <= 0 || edge_count <= 0)) return; + depth_left--; + edge_count--; + paint.dispatch (this); + depth_left++; +} + +void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const +{ + const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList (); + for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++) + { + const Paint &paint = paint_offset_lists.get_paint (i); + c->funcs->push_group (c->data); + c->recurse (paint); + c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER); + } +} +void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const +{ + const COLR *colr_table = c->get_colr_table (); + const Paint *paint = colr_table->get_base_glyph_paint (gid); + + hb_glyph_extents_t extents = {0}; + bool has_clip_box = colr_table->get_clip (gid, &extents, c->instancer); + + if (has_clip_box) + c->funcs->push_clip_rectangle (c->data, + extents.x_bearing, + extents.y_bearing + extents.height, + extents.x_bearing + extents.width, + extents.y_bearing); + + if (paint) + c->recurse (*paint); + + if (has_clip_box) + c->funcs->pop_clip (c->data); +} + +} /* namespace OT */ -#endif /* HB_OT_COLOR_COLR_TABLE_HH */ +#endif /* OT_COLOR_COLR_COLR_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colrv1-closure.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/colrv1-closure.hh similarity index 94% rename from src/java.desktop/share/native/libharfbuzz/hb-ot-color-colrv1-closure.hh rename to src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/colrv1-closure.hh index fbaf2ec26b6..705863d4ade 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-colrv1-closure.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/COLR/colrv1-closure.hh @@ -24,12 +24,11 @@ * */ -#ifndef HB_OT_COLR_COLRV1_CLOSURE_HH -#define HB_OT_COLR_COLRV1_CLOSURE_HH +#ifndef OT_COLOR_COLR_COLRV1_CLOSURE_HH +#define OT_COLOR_COLR_COLRV1_CLOSURE_HH -#include "hb-open-type.hh" -#include "hb-ot-layout-common.hh" -#include "hb-ot-color-colr-table.hh" +#include "../../../hb-open-type.hh" +#include "COLR.hh" /* * COLR -- Color @@ -105,4 +104,4 @@ HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) cons } /* namespace OT */ -#endif /* HB_OT_COLR_COLRV1_CLOSURE_HH */ +#endif /* OT_COLOR_COLR_COLRV1_CLOSURE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh similarity index 97% rename from src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh rename to src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh index 5558d518190..e177190710c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-cpal-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/CPAL/CPAL.hh @@ -25,12 +25,12 @@ * Google Author(s): Sascha Brawer */ -#ifndef HB_OT_COLOR_CPAL_TABLE_HH -#define HB_OT_COLOR_CPAL_TABLE_HH +#ifndef OT_COLOR_CPAL_CPAL_HH +#define OT_COLOR_CPAL_CPAL_HH -#include "hb-open-type.hh" -#include "hb-ot-color.h" -#include "hb-ot-name.h" +#include "../../../hb-open-type.hh" +#include "../../../hb-ot-color.h" +#include "../../../hb-ot-name.h" /* @@ -239,7 +239,7 @@ struct CPAL TRACE_SUBSET (this); if (!numPalettes) return_trace (false); - const hb_map_t *color_index_map = c->plan->colr_palettes; + const hb_map_t *color_index_map = &c->plan->colr_palettes; if (color_index_map->is_empty ()) return_trace (false); hb_set_t retained_color_indices; @@ -319,4 +319,4 @@ struct CPAL } /* namespace OT */ -#endif /* HB_OT_COLOR_CPAL_TABLE_HH */ +#endif /* OT_COLOR_CPAL_CPAL_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh similarity index 88% rename from src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh rename to src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh index a46b2264770..55d770e9283 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-sbix-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/sbix/sbix.hh @@ -25,11 +25,11 @@ * Google Author(s): Calder Kitagawa */ -#ifndef HB_OT_COLOR_SBIX_TABLE_HH -#define HB_OT_COLOR_SBIX_TABLE_HH +#ifndef OT_COLOR_SBIX_SBIX_HH +#define OT_COLOR_SBIX_SBIX_HH -#include "hb-open-type.hh" -#include "hb-ot-layout-common.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-paint.hh" /* * sbix -- Standard Bitmap Graphics @@ -213,10 +213,11 @@ struct sbix bool get_extents (hb_font_t *font, hb_codepoint_t glyph, - hb_glyph_extents_t *extents) const + hb_glyph_extents_t *extents, + bool scale = true) const { /* We only support PNG right now, and following function checks type. */ - return get_png_extents (font, glyph, extents); + return get_png_extents (font, glyph, extents, scale); } hb_blob_t *reference_png (hb_font_t *font, @@ -231,6 +232,37 @@ struct sbix num_glyphs, available_ppem); } + bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const + { + if (!has_data ()) + return false; + + int x_offset = 0, y_offset = 0; + unsigned int strike_ppem = 0; + hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem); + hb_glyph_extents_t extents; + hb_glyph_extents_t pixel_extents; + + if (blob == hb_blob_get_empty ()) + return false; + + if (!hb_font_get_glyph_extents (font, glyph, &extents)) + return false; + + if (unlikely (!get_extents (font, glyph, &pixel_extents, false))) + return false; + + bool ret = funcs->image (data, + blob, + pixel_extents.width, -pixel_extents.height, + HB_PAINT_IMAGE_FORMAT_PNG, + font->slant_xy, + &extents); + + hb_blob_destroy (blob); + return ret; + } + private: const SBIXStrike &choose_strike (hb_font_t *font) const @@ -285,7 +317,8 @@ struct sbix bool get_png_extents (hb_font_t *font, hb_codepoint_t glyph, - hb_glyph_extents_t *extents) const + hb_glyph_extents_t *extents, + bool scale = true) const { /* Following code is safe to call even without data. * But faster to short-circuit. */ @@ -310,22 +343,18 @@ struct sbix extents->height = -1 * png.IHDR.height; /* Convert to font units. */ - if (strike_ppem) + if (strike_ppem && scale) { float scale = font->face->get_upem () / (float) strike_ppem; - extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale); - extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale); - extents->width = font->em_scalef_x (extents->width * scale); - extents->height = font->em_scalef_y (extents->height * scale); - } - else - { - extents->x_bearing = font->em_scale_x (extents->x_bearing); - extents->y_bearing = font->em_scale_y (extents->y_bearing); - extents->width = font->em_scale_x (extents->width); - extents->height = font->em_scale_y (extents->height); + extents->x_bearing = roundf (extents->x_bearing * scale); + extents->y_bearing = roundf (extents->y_bearing * scale); + extents->width = roundf (extents->width * scale); + extents->height = roundf (extents->height * scale); } + if (scale) + font->scale_glyph_extents (extents); + hb_blob_destroy (blob); return strike_ppem; @@ -420,4 +449,4 @@ struct sbix_accelerator_t : sbix::accelerator_t { } /* namespace OT */ -#endif /* HB_OT_COLOR_SBIX_TABLE_HH */ +#endif /* OT_COLOR_SBIX_SBIX_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh b/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh similarity index 83% rename from src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh rename to src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh index 8d4dee92878..c8ff6ab743e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color-svg-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Color/svg/svg.hh @@ -22,10 +22,12 @@ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. */ -#ifndef HB_OT_COLOR_SVG_TABLE_HH -#define HB_OT_COLOR_SVG_TABLE_HH +#ifndef OT_COLOR_SVG_SVG_HH +#define OT_COLOR_SVG_SVG_HH -#include "hb-open-type.hh" +#include "../../../hb-open-type.hh" +#include "../../../hb-blob.hh" +#include "../../../hb-paint.hh" /* * SVG -- SVG (Scalable Vector Graphics) @@ -91,8 +93,31 @@ struct SVG bool has_data () const { return table->has_data (); } + bool paint_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const + { + if (!has_data ()) + return false; + + hb_blob_t *blob = reference_blob_for_glyph (glyph); + + if (blob == hb_blob_get_empty ()) + return false; + + funcs->image (data, + blob, + 0, 0, + HB_PAINT_IMAGE_FORMAT_SVG, + font->slant_xy, + nullptr); + + hb_blob_destroy (blob); + return true; + } + private: hb_blob_ptr_t table; + public: + DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t)); }; const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const @@ -123,4 +148,4 @@ struct SVG_accelerator_t : SVG::accelerator_t { } /* namespace OT */ -#endif /* HB_OT_COLOR_SVG_TABLE_HH */ +#endif /* OT_COLOR_SVG_SVG_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh new file mode 100644 index 00000000000..016a9402e3c --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/Coverage.hh @@ -0,0 +1,337 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod, Garret Rieger + */ + +#ifndef OT_LAYOUT_COMMON_COVERAGE_HH +#define OT_LAYOUT_COMMON_COVERAGE_HH + +#include "../types.hh" +#include "CoverageFormat1.hh" +#include "CoverageFormat2.hh" + +namespace OT { +namespace Layout { +namespace Common { + +template +static inline void Coverage_serialize (hb_serialize_context_t *c, + Iterator it); + +struct Coverage +{ + + protected: + union { + HBUINT16 format; /* Format identifier */ + CoverageFormat1_3 format1; + CoverageFormat2_4 format2; +#ifndef HB_NO_BEYOND_64K + CoverageFormat1_3format3; + CoverageFormat2_4format4; +#endif + } u; + public: + DEFINE_SIZE_UNION (2, format); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) + { + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); +#ifndef HB_NO_BEYOND_64K + case 3: return_trace (u.format3.sanitize (c)); + case 4: return_trace (u.format4.sanitize (c)); +#endif + default:return_trace (true); + } + } + + /* Has interface. */ + unsigned operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k] != NOT_COVERED; } + /* Predicate. */ + bool operator () (hb_codepoint_t k) const { return has (k); } + + unsigned int get (hb_codepoint_t k) const { return get_coverage (k); } + unsigned int get_coverage (hb_codepoint_t glyph_id) const + { + switch (u.format) { + case 1: return u.format1.get_coverage (glyph_id); + case 2: return u.format2.get_coverage (glyph_id); +#ifndef HB_NO_BEYOND_64K + case 3: return u.format3.get_coverage (glyph_id); + case 4: return u.format4.get_coverage (glyph_id); +#endif + default:return NOT_COVERED; + } + } + + unsigned get_population () const + { + switch (u.format) { + case 1: return u.format1.get_population (); + case 2: return u.format2.get_population (); +#ifndef HB_NO_BEYOND_64K + case 3: return u.format3.get_population (); + case 4: return u.format4.get_population (); +#endif + default:return NOT_COVERED; + } + } + + template + bool serialize (hb_serialize_context_t *c, Iterator glyphs) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + + unsigned count = 0; + unsigned num_ranges = 0; + hb_codepoint_t last = (hb_codepoint_t) -2; + for (auto g: glyphs) + { + if (last + 1 != g) + num_ranges++; + last = g; + count++; + } + u.format = count <= num_ranges * 3 ? 1 : 2; + +#ifndef HB_NO_BEYOND_64K + if (count && last > 0xFFFFu) + u.format += 2; +#endif + + switch (u.format) + { + case 1: return_trace (u.format1.serialize (c, glyphs)); + case 2: return_trace (u.format2.serialize (c, glyphs)); +#ifndef HB_NO_BEYOND_64K + case 3: return_trace (u.format3.serialize (c, glyphs)); + case 4: return_trace (u.format4.serialize (c, glyphs)); +#endif + default:return_trace (false); + } + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto it = + + iter () + | hb_take (c->plan->source->get_num_glyphs ()) + | hb_filter (c->plan->glyph_map_gsub) + | hb_map_retains_sorting (c->plan->glyph_map_gsub) + ; + + // Cache the iterator result as it will be iterated multiple times + // by the serialize code below. + hb_sorted_vector_t glyphs (it); + Coverage_serialize (c->serializer, glyphs.iter ()); + return_trace (bool (glyphs)); + } + + bool intersects (const hb_set_t *glyphs) const + { + switch (u.format) + { + case 1: return u.format1.intersects (glyphs); + case 2: return u.format2.intersects (glyphs); +#ifndef HB_NO_BEYOND_64K + case 3: return u.format3.intersects (glyphs); + case 4: return u.format4.intersects (glyphs); +#endif + default:return false; + } + } + bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { + switch (u.format) + { + case 1: return u.format1.intersects_coverage (glyphs, index); + case 2: return u.format2.intersects_coverage (glyphs, index); +#ifndef HB_NO_BEYOND_64K + case 3: return u.format3.intersects_coverage (glyphs, index); + case 4: return u.format4.intersects_coverage (glyphs, index); +#endif + default:return false; + } + } + + /* Might return false if array looks unsorted. + * Used for faster rejection of corrupt data. */ + template + bool collect_coverage (set_t *glyphs) const + { + switch (u.format) + { + case 1: return u.format1.collect_coverage (glyphs); + case 2: return u.format2.collect_coverage (glyphs); +#ifndef HB_NO_BEYOND_64K + case 3: return u.format3.collect_coverage (glyphs); + case 4: return u.format4.collect_coverage (glyphs); +#endif + default:return false; + } + } + + template + void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const + { + switch (u.format) + { + case 1: return u.format1.intersect_set (glyphs, intersect_glyphs); + case 2: return u.format2.intersect_set (glyphs, intersect_glyphs); +#ifndef HB_NO_BEYOND_64K + case 3: return u.format3.intersect_set (glyphs, intersect_glyphs); + case 4: return u.format4.intersect_set (glyphs, intersect_glyphs); +#endif + default:return ; + } + } + + struct iter_t : hb_iter_with_fallback_t + { + static constexpr bool is_sorted_iterator = true; + iter_t (const Coverage &c_ = Null (Coverage)) + { + hb_memset (this, 0, sizeof (*this)); + format = c_.u.format; + switch (format) + { + case 1: u.format1.init (c_.u.format1); return; + case 2: u.format2.init (c_.u.format2); return; +#ifndef HB_NO_BEYOND_64K + case 3: u.format3.init (c_.u.format3); return; + case 4: u.format4.init (c_.u.format4); return; +#endif + default: return; + } + } + bool __more__ () const + { + switch (format) + { + case 1: return u.format1.__more__ (); + case 2: return u.format2.__more__ (); +#ifndef HB_NO_BEYOND_64K + case 3: return u.format3.__more__ (); + case 4: return u.format4.__more__ (); +#endif + default:return false; + } + } + void __next__ () + { + switch (format) + { + case 1: u.format1.__next__ (); break; + case 2: u.format2.__next__ (); break; +#ifndef HB_NO_BEYOND_64K + case 3: u.format3.__next__ (); break; + case 4: u.format4.__next__ (); break; +#endif + default: break; + } + } + typedef hb_codepoint_t __item_t__; + __item_t__ __item__ () const { return get_glyph (); } + + hb_codepoint_t get_glyph () const + { + switch (format) + { + case 1: return u.format1.get_glyph (); + case 2: return u.format2.get_glyph (); +#ifndef HB_NO_BEYOND_64K + case 3: return u.format3.get_glyph (); + case 4: return u.format4.get_glyph (); +#endif + default:return 0; + } + } + bool operator != (const iter_t& o) const + { + if (unlikely (format != o.format)) return true; + switch (format) + { + case 1: return u.format1 != o.u.format1; + case 2: return u.format2 != o.u.format2; +#ifndef HB_NO_BEYOND_64K + case 3: return u.format3 != o.u.format3; + case 4: return u.format4 != o.u.format4; +#endif + default:return false; + } + } + iter_t __end__ () const + { + iter_t it = {}; + it.format = format; + switch (format) + { + case 1: it.u.format1 = u.format1.__end__ (); break; + case 2: it.u.format2 = u.format2.__end__ (); break; +#ifndef HB_NO_BEYOND_64K + case 3: it.u.format3 = u.format3.__end__ (); break; + case 4: it.u.format4 = u.format4.__end__ (); break; +#endif + default: break; + } + return it; + } + + private: + unsigned int format; + union { +#ifndef HB_NO_BEYOND_64K + CoverageFormat2_4::iter_t format4; /* Put this one first since it's larger; helps shut up compiler. */ + CoverageFormat1_3::iter_t format3; +#endif + CoverageFormat2_4::iter_t format2; /* Put this one first since it's larger; helps shut up compiler. */ + CoverageFormat1_3::iter_t format1; + } u; + }; + iter_t iter () const { return iter_t (*this); } +}; + +template +static inline void +Coverage_serialize (hb_serialize_context_t *c, + Iterator it) +{ c->start_embed ()->serialize (c, it); } + +} +} +} + +#endif // #ifndef OT_LAYOUT_COMMON_COVERAGE_HH diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh new file mode 100644 index 00000000000..1fa92df3620 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat1.hh @@ -0,0 +1,133 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod, Garret Rieger + */ + + +#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH +#define OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH + +namespace OT { +namespace Layout { +namespace Common { + +#define NOT_COVERED ((unsigned int) -1) + +template +struct CoverageFormat1_3 +{ + friend struct Coverage; + + protected: + HBUINT16 coverageFormat; /* Format identifier--format = 1 */ + SortedArray16Of + glyphArray; /* Array of GlyphIDs--in numerical order */ + public: + DEFINE_SIZE_ARRAY (4, glyphArray); + + private: + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (glyphArray.sanitize (c)); + } + + unsigned int get_coverage (hb_codepoint_t glyph_id) const + { + unsigned int i; + glyphArray.bfind (glyph_id, &i, HB_NOT_FOUND_STORE, NOT_COVERED); + return i; + } + + unsigned get_population () const + { + return glyphArray.len; + } + + template + bool serialize (hb_serialize_context_t *c, Iterator glyphs) + { + TRACE_SERIALIZE (this); + return_trace (glyphArray.serialize (c, glyphs)); + } + + bool intersects (const hb_set_t *glyphs) const + { + if (glyphArray.len > glyphs->get_population () * hb_bit_storage ((unsigned) glyphArray.len) / 2) + { + for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + if (get_coverage (g) != NOT_COVERED) + return true; + return false; + } + + for (const auto& g : glyphArray.as_array ()) + if (glyphs->has (g)) + return true; + return false; + } + bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { return glyphs->has (glyphArray[index]); } + + template + void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const + { + unsigned count = glyphArray.len; + for (unsigned i = 0; i < count; i++) + if (glyphs.has (glyphArray[i])) + intersect_glyphs << glyphArray[i]; + } + + template + bool collect_coverage (set_t *glyphs) const + { return glyphs->add_sorted_array (glyphArray.as_array ()); } + + public: + /* Older compilers need this to be public. */ + struct iter_t + { + void init (const struct CoverageFormat1_3 &c_) { c = &c_; i = 0; } + bool __more__ () const { return i < c->glyphArray.len; } + void __next__ () { i++; } + hb_codepoint_t get_glyph () const { return c->glyphArray[i]; } + bool operator != (const iter_t& o) const + { return i != o.i; } + iter_t __end__ () const { iter_t it; it.init (*c); it.i = c->glyphArray.len; return it; } + + private: + const struct CoverageFormat1_3 *c; + unsigned int i; + }; + private: +}; + +} +} +} + +#endif // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT1_HH diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh new file mode 100644 index 00000000000..2650d198f4c --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/CoverageFormat2.hh @@ -0,0 +1,232 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod, Garret Rieger + */ + +#ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH +#define OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH + +#include "RangeRecord.hh" + +namespace OT { +namespace Layout { +namespace Common { + +template +struct CoverageFormat2_4 +{ + friend struct Coverage; + + protected: + HBUINT16 coverageFormat; /* Format identifier--format = 2 */ + SortedArray16Of> + rangeRecord; /* Array of glyph ranges--ordered by + * Start GlyphID. rangeCount entries + * long */ + public: + DEFINE_SIZE_ARRAY (4, rangeRecord); + + private: + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (rangeRecord.sanitize (c)); + } + + unsigned int get_coverage (hb_codepoint_t glyph_id) const + { + const RangeRecord &range = rangeRecord.bsearch (glyph_id); + return likely (range.first <= range.last) + ? (unsigned int) range.value + (glyph_id - range.first) + : NOT_COVERED; + } + + unsigned get_population () const + { + typename Types::large_int ret = 0; + for (const auto &r : rangeRecord) + ret += r.get_population (); + return ret > UINT_MAX ? UINT_MAX : (unsigned) ret; + } + + template + bool serialize (hb_serialize_context_t *c, Iterator glyphs) + { + TRACE_SERIALIZE (this); + if (unlikely (!c->extend_min (this))) return_trace (false); + + unsigned num_ranges = 0; + hb_codepoint_t last = (hb_codepoint_t) -2; + for (auto g: glyphs) + { + if (last + 1 != g) + num_ranges++; + last = g; + } + + if (unlikely (!rangeRecord.serialize (c, num_ranges))) return_trace (false); + if (!num_ranges) return_trace (true); + + unsigned count = 0; + unsigned range = (unsigned) -1; + last = (hb_codepoint_t) -2; + for (auto g: glyphs) + { + if (last + 1 != g) + { + range++; + rangeRecord[range].first = g; + rangeRecord[range].value = count; + } + rangeRecord[range].last = g; + last = g; + count++; + } + + return_trace (true); + } + + bool intersects (const hb_set_t *glyphs) const + { + if (rangeRecord.len > glyphs->get_population () * hb_bit_storage ((unsigned) rangeRecord.len) / 2) + { + for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + if (get_coverage (g) != NOT_COVERED) + return true; + return false; + } + + return hb_any (+ hb_iter (rangeRecord) + | hb_map ([glyphs] (const RangeRecord &range) { return range.intersects (*glyphs); })); + } + bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const + { + auto *range = rangeRecord.as_array ().bsearch (index); + if (range) + return range->intersects (*glyphs); + return false; + } + + template + void intersect_set (const hb_set_t &glyphs, IterableOut&& intersect_glyphs) const + { + /* Break out of loop for overlapping, broken, tables, + * to avoid fuzzer timouts. */ + hb_codepoint_t last = 0; + for (const auto& range : rangeRecord) + { + if (unlikely (range.first < last)) + break; + last = range.last; + for (hb_codepoint_t g = range.first - 1; + glyphs.next (&g) && g <= last;) + intersect_glyphs << g; + } + } + + template + bool collect_coverage (set_t *glyphs) const + { + for (const auto& range: rangeRecord) + if (unlikely (!range.collect_coverage (glyphs))) + return false; + return true; + } + + public: + /* Older compilers need this to be public. */ + struct iter_t + { + void init (const CoverageFormat2_4 &c_) + { + c = &c_; + coverage = 0; + i = 0; + j = c->rangeRecord.len ? c->rangeRecord[0].first : 0; + if (unlikely (c->rangeRecord[0].first > c->rangeRecord[0].last)) + { + /* Broken table. Skip. */ + i = c->rangeRecord.len; + j = 0; + } + } + bool __more__ () const { return i < c->rangeRecord.len; } + void __next__ () + { + if (j >= c->rangeRecord[i].last) + { + i++; + if (__more__ ()) + { + unsigned int old = coverage; + j = c->rangeRecord[i].first; + coverage = c->rangeRecord[i].value; + if (unlikely (coverage != old + 1)) + { + /* Broken table. Skip. Important to avoid DoS. + * Also, our callers depend on coverage being + * consecutive and monotonically increasing, + * ie. iota(). */ + i = c->rangeRecord.len; + j = 0; + return; + } + } + else + j = 0; + return; + } + coverage++; + j++; + } + hb_codepoint_t get_glyph () const { return j; } + bool operator != (const iter_t& o) const + { return i != o.i || j != o.j; } + iter_t __end__ () const + { + iter_t it; + it.init (*c); + it.i = c->rangeRecord.len; + it.j = 0; + return it; + } + + private: + const struct CoverageFormat2_4 *c; + unsigned int i, coverage; + hb_codepoint_t j; + }; + private: +}; + +} +} +} + +#endif // #ifndef OT_LAYOUT_COMMON_COVERAGEFORMAT2_HH diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh new file mode 100644 index 00000000000..a62629fad34 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/Common/RangeRecord.hh @@ -0,0 +1,85 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod, Garret Rieger + */ + +#ifndef OT_LAYOUT_COMMON_RANGERECORD_HH +#define OT_LAYOUT_COMMON_RANGERECORD_HH + +namespace OT { +namespace Layout { +namespace Common { + +template +struct RangeRecord +{ + typename Types::HBGlyphID first; /* First GlyphID in the range */ + typename Types::HBGlyphID last; /* Last GlyphID in the range */ + HBUINT16 value; /* Value */ + + DEFINE_SIZE_STATIC (2 + 2 * Types::size); + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + int cmp (hb_codepoint_t g) const + { return g < first ? -1 : g <= last ? 0 : +1; } + + unsigned get_population () const + { + if (unlikely (last < first)) return 0; + return (last - first + 1); + } + + bool intersects (const hb_set_t &glyphs) const + { return glyphs.intersects (first, last); } + + template + bool collect_coverage (set_t *glyphs) const + { return glyphs->add_range (first, last); } +}; + +} +} +} + +// TODO(garretrieger): This was previously implemented using +// DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (OT, RangeRecord, 9); +// but that only works when there is only a single namespace level. +// The macro should probably be fixed so it can work in this situation. +extern HB_INTERNAL const unsigned char _hb_Null_OT_RangeRecord[9]; +template +struct Null> { + static OT::Layout::Common::RangeRecord const & get_null () { + return *reinterpret_cast *> (_hb_Null_OT_RangeRecord); + } +}; + + +#endif // #ifndef OT_LAYOUT_COMMON_RANGERECORD_HH diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh new file mode 100644 index 00000000000..0cf5753b0e5 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GDEF/GDEF.hh @@ -0,0 +1,918 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010,2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#ifndef OT_LAYOUT_GDEF_GDEF_HH +#define OT_LAYOUT_GDEF_GDEF_HH + +#include "../../../hb-ot-layout-common.hh" + +#include "../../../hb-font.hh" + + +namespace OT { + + +/* + * Attachment List Table + */ + +/* Array of contour point indices--in increasing numerical order */ +struct AttachPoint : Array16Of +{ + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out)) return_trace (false); + + return_trace (out->serialize (c->serializer, + iter ())); + } +}; + +struct AttachList +{ + unsigned int get_attach_points (hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *point_count /* IN/OUT */, + unsigned int *point_array /* OUT */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (index == NOT_COVERED) + { + if (point_count) + *point_count = 0; + return 0; + } + + const AttachPoint &points = this+attachPoint[index]; + + if (point_count) + { + + points.as_array ().sub_array (start_offset, point_count) + | hb_sink (hb_array (point_array, *point_count)) + ; + } + + return points.len; + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, attachPoint) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this)); + } + + protected: + Offset16To + coverage; /* Offset to Coverage table -- from + * beginning of AttachList table */ + Array16OfOffset16To + attachPoint; /* Array of AttachPoint tables + * in Coverage Index order */ + public: + DEFINE_SIZE_ARRAY (4, attachPoint); +}; + +/* + * Ligature Caret Table + */ + +struct CaretValueFormat1 +{ + friend struct CaretValue; + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + return_trace (true); + } + + private: + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const + { + return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + HBUINT16 caretValueFormat; /* Format identifier--format = 1 */ + FWORD coordinate; /* X or Y value, in design units */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct CaretValueFormat2 +{ + friend struct CaretValue; + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (this); + if (unlikely (!out)) return_trace (false); + return_trace (true); + } + + private: + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const + { + hb_position_t x, y; + font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y); + return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this)); + } + + protected: + HBUINT16 caretValueFormat; /* Format identifier--format = 2 */ + HBUINT16 caretValuePoint; /* Contour point index on glyph */ + public: + DEFINE_SIZE_STATIC (4); +}; + +struct CaretValueFormat3 +{ + friend struct CaretValue; + + hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, + const VariationStore &var_store) const + { + return HB_DIRECTION_IS_HORIZONTAL (direction) ? + font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) : + font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out)) return_trace (false); + if (!c->serializer->embed (caretValueFormat)) return_trace (false); + if (!c->serializer->embed (coordinate)) return_trace (false); + + unsigned varidx = (this+deviceTable).get_variation_index (); + if (c->plan->layout_variation_idx_delta_map.has (varidx)) + { + int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx)); + if (delta != 0) + { + if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } + } + + if (c->plan->all_axes_pinned) + return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + + if (!c->serializer->embed (deviceTable)) + return_trace (false); + + return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out), + hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { (this+deviceTable).collect_variation_indices (c); } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && deviceTable.sanitize (c, this)); + } + + protected: + HBUINT16 caretValueFormat; /* Format identifier--format = 3 */ + FWORD coordinate; /* X or Y value, in design units */ + Offset16To + deviceTable; /* Offset to Device table for X or Y + * value--from beginning of CaretValue + * table */ + public: + DEFINE_SIZE_STATIC (6); +}; + +struct CaretValue +{ + hb_position_t get_caret_value (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const VariationStore &var_store) const + { + switch (u.format) { + case 1: return u.format1.get_caret_value (font, direction); + case 2: return u.format2.get_caret_value (font, direction, glyph_id); + case 3: return u.format3.get_caret_value (font, direction, var_store); + default:return 0; + } + } + + template + typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const + { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); + TRACE_DISPATCH (this, u.format); + switch (u.format) { + case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); + case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); + default:return_trace (c->default_return_value ()); + } + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + switch (u.format) { + case 1: + case 2: + return; + case 3: + u.format3.collect_variation_indices (c); + return; + default: return; + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { + case 1: return_trace (u.format1.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + case 3: return_trace (u.format3.sanitize (c)); + default:return_trace (true); + } + } + + protected: + union { + HBUINT16 format; /* Format identifier */ + CaretValueFormat1 format1; + CaretValueFormat2 format2; + CaretValueFormat3 format3; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + +struct LigGlyph +{ + unsigned get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const VariationStore &var_store, + unsigned start_offset, + unsigned *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const + { + if (caret_count) + { + + carets.as_array ().sub_array (start_offset, caret_count) + | hb_map (hb_add (this)) + | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); }) + | hb_sink (hb_array (caret_array, *caret_count)) + ; + } + + return carets.len; + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + + hb_iter (carets) + | hb_apply (subset_offset_array (c, out->carets, this)) + ; + + return_trace (bool (out->carets)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + for (const Offset16To& offset : carets.iter ()) + (this+offset).collect_variation_indices (c); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (carets.sanitize (c, this)); + } + + protected: + Array16OfOffset16To + carets; /* Offset array of CaretValue tables + * --from beginning of LigGlyph table + * --in increasing coordinate order */ + public: + DEFINE_SIZE_ARRAY (2, carets); +}; + +struct LigCaretList +{ + unsigned int get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + const VariationStore &var_store, + unsigned int start_offset, + unsigned int *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const + { + unsigned int index = (this+coverage).get_coverage (glyph_id); + if (index == NOT_COVERED) + { + if (caret_count) + *caret_count = 0; + return 0; + } + const LigGlyph &lig_glyph = this+ligGlyph[index]; + return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + hb_sorted_vector_t new_coverage; + + hb_zip (this+coverage, ligGlyph) + | hb_filter (glyphset, hb_first) + | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second) + | hb_map (hb_first) + | hb_map (glyph_map) + | hb_sink (new_coverage) + ; + out->coverage.serialize_serialize (c->serializer, new_coverage.iter ()); + return_trace (bool (new_coverage)); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { + + hb_zip (this+coverage, ligGlyph) + | hb_filter (c->glyph_set, hb_first) + | hb_map (hb_second) + | hb_map (hb_add (this)) + | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); }) + ; + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this)); + } + + protected: + Offset16To + coverage; /* Offset to Coverage table--from + * beginning of LigCaretList table */ + Array16OfOffset16To + ligGlyph; /* Array of LigGlyph tables + * in Coverage Index order */ + public: + DEFINE_SIZE_ARRAY (4, ligGlyph); +}; + + +struct MarkGlyphSetsFormat1 +{ + bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->format = format; + + bool ret = true; + for (const Offset32To& offset : coverage.iter ()) + { + auto *o = out->coverage.serialize_append (c->serializer); + if (unlikely (!o)) + { + ret = false; + break; + } + + //not using o->serialize_subset (c, offset, this, out) here because + //OTS doesn't allow null offset. + //See issue: https://github.com/khaledhosny/ots/issues/172 + c->serializer->push (); + c->dispatch (this+offset); + c->serializer->add_link (*o, c->serializer->pop_pack ()); + } + + return_trace (ret && out->coverage.len); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (coverage.sanitize (c, this)); + } + + protected: + HBUINT16 format; /* Format identifier--format = 1 */ + Array16Of> + coverage; /* Array of long offsets to mark set + * coverage tables */ + public: + DEFINE_SIZE_ARRAY (4, coverage); +}; + +struct MarkGlyphSets +{ + bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { + switch (u.format) { + case 1: return u.format1.covers (set_index, glyph_id); + default:return false; + } + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + switch (u.format) { + case 1: return_trace (u.format1.subset (c)); + default:return_trace (false); + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { + case 1: return_trace (u.format1.sanitize (c)); + default:return_trace (true); + } + } + + protected: + union { + HBUINT16 format; /* Format identifier */ + MarkGlyphSetsFormat1 format1; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + + +/* + * GDEF -- Glyph Definition + * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef + */ + + +template +struct GDEFVersion1_2 +{ + friend struct GDEF; + + protected: + FixedVersion<>version; /* Version of the GDEF table--currently + * 0x00010003u */ + typename Types::template OffsetTo + glyphClassDef; /* Offset to class definition table + * for glyph type--from beginning of + * GDEF header (may be Null) */ + typename Types::template OffsetTo + attachList; /* Offset to list of glyphs with + * attachment points--from beginning + * of GDEF header (may be Null) */ + typename Types::template OffsetTo + ligCaretList; /* Offset to list of positioning points + * for ligature carets--from beginning + * of GDEF header (may be Null) */ + typename Types::template OffsetTo + markAttachClassDef; /* Offset to class definition table for + * mark attachment type--from beginning + * of GDEF header (may be Null) */ + typename Types::template OffsetTo + markGlyphSetsDef; /* Offset to the table of mark set + * definitions--from beginning of GDEF + * header (may be NULL). Introduced + * in version 0x00010002. */ + Offset32To + varStore; /* Offset to the table of Item Variation + * Store--from beginning of GDEF + * header (may be NULL). Introduced + * in version 0x00010003. */ + public: + DEFINE_SIZE_MIN (4 + 4 * Types::size); + + unsigned int get_size () const + { + return min_size + + (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) + + (version.to_int () >= 0x00010003u ? varStore.static_size : 0); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (version.sanitize (c) && + glyphClassDef.sanitize (c, this) && + attachList.sanitize (c, this) && + ligCaretList.sanitize (c, this) && + markAttachClassDef.sanitize (c, this) && + (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) && + (version.to_int () < 0x00010003u || varStore.sanitize (c, this))); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + auto *out = c->serializer->embed (*this); + if (unlikely (!out)) return_trace (false); + + bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true); + bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this); + bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this); + bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true); + + bool subset_markglyphsetsdef = false; + if (version.to_int () >= 0x00010002u) + { + subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this); + } + + bool subset_varstore = false; + if (version.to_int () >= 0x00010003u) + { + if (c->plan->all_axes_pinned) + out->varStore = 0; + else + subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ()); + } + + if (subset_varstore) + { + out->version.minor = 3; + } else if (subset_markglyphsetsdef) { + out->version.minor = 2; + } else { + out->version.minor = 0; + } + + return_trace (subset_glyphclassdef || subset_attachlist || + subset_ligcaretlist || subset_markattachclassdef || + (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) || + (out->version.to_int () >= 0x00010003u && subset_varstore)); + } +}; + +struct GDEF +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF; + + enum GlyphClasses { + UnclassifiedGlyph = 0, + BaseGlyph = 1, + LigatureGlyph = 2, + MarkGlyph = 3, + ComponentGlyph = 4 + }; + + unsigned int get_size () const + { + switch (u.version.major) { + case 1: return u.version1.get_size (); +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.get_size (); +#endif + default: return u.version.static_size; + } + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (unlikely (!u.version.sanitize (c))) return_trace (false); + switch (u.version.major) { + case 1: return_trace (u.version1.sanitize (c)); +#ifndef HB_NO_BEYOND_64K + case 2: return_trace (u.version2.sanitize (c)); +#endif + default: return_trace (true); + } + } + + bool subset (hb_subset_context_t *c) const + { + switch (u.version.major) { + case 1: return u.version1.subset (c); +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.subset (c); +#endif + default: return false; + } + } + + bool has_glyph_classes () const + { + switch (u.version.major) { + case 1: return u.version1.glyphClassDef != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.glyphClassDef != 0; +#endif + default: return false; + } + } + const ClassDef &get_glyph_class_def () const + { + switch (u.version.major) { + case 1: return this+u.version1.glyphClassDef; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.glyphClassDef; +#endif + default: return Null(ClassDef); + } + } + bool has_attach_list () const + { + switch (u.version.major) { + case 1: return u.version1.attachList != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.attachList != 0; +#endif + default: return false; + } + } + const AttachList &get_attach_list () const + { + switch (u.version.major) { + case 1: return this+u.version1.attachList; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.attachList; +#endif + default: return Null(AttachList); + } + } + bool has_lig_carets () const + { + switch (u.version.major) { + case 1: return u.version1.ligCaretList != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.ligCaretList != 0; +#endif + default: return false; + } + } + const LigCaretList &get_lig_caret_list () const + { + switch (u.version.major) { + case 1: return this+u.version1.ligCaretList; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.ligCaretList; +#endif + default: return Null(LigCaretList); + } + } + bool has_mark_attachment_types () const + { + switch (u.version.major) { + case 1: return u.version1.markAttachClassDef != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.markAttachClassDef != 0; +#endif + default: return false; + } + } + const ClassDef &get_mark_attach_class_def () const + { + switch (u.version.major) { + case 1: return this+u.version1.markAttachClassDef; +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.markAttachClassDef; +#endif + default: return Null(ClassDef); + } + } + bool has_mark_glyph_sets () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.markGlyphSetsDef != 0; +#endif + default: return false; + } + } + const MarkGlyphSets &get_mark_glyph_sets () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets); +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.markGlyphSetsDef; +#endif + default: return Null(MarkGlyphSets); + } + } + bool has_var_store () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0; +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.varStore != 0; +#endif + default: return false; + } + } + const VariationStore &get_var_store () const + { + switch (u.version.major) { + case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore); +#ifndef HB_NO_BEYOND_64K + case 2: return this+u.version2.varStore; +#endif + default: return Null(VariationStore); + } + } + + + bool has_data () const { return u.version.to_int (); } + unsigned int get_glyph_class (hb_codepoint_t glyph) const + { return get_glyph_class_def ().get_class (glyph); } + void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const + { get_glyph_class_def ().collect_class (glyphs, klass); } + + unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const + { return get_mark_attach_class_def ().get_class (glyph); } + + unsigned int get_attach_points (hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *point_count /* IN/OUT */, + unsigned int *point_array /* OUT */) const + { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); } + + unsigned int get_lig_carets (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t glyph_id, + unsigned int start_offset, + unsigned int *caret_count /* IN/OUT */, + hb_position_t *caret_array /* OUT */) const + { return get_lig_caret_list ().get_lig_carets (font, + direction, glyph_id, get_var_store(), + start_offset, caret_count, caret_array); } + + bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const + { return get_mark_glyph_sets ().covers (set_index, glyph_id); } + + /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing + * glyph class and other bits, and high 8-bit the mark attachment type (if any). + * Not to be confused with lookup_props which is very similar. */ + unsigned int get_glyph_props (hb_codepoint_t glyph) const + { + unsigned int klass = get_glyph_class (glyph); + + static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), ""); + static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), ""); + static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), ""); + + switch (klass) { + default: return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED; + case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH; + case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; + case MarkGlyph: + klass = get_mark_attachment_type (glyph); + return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8); + } + } + + HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, + hb_face_t *face) const; + + struct accelerator_t + { + accelerator_t (hb_face_t *face) + { + table = hb_sanitize_context_t ().reference_table (face); + if (unlikely (table->is_blocklisted (table.get_blob (), face))) + { + hb_blob_destroy (table.get_blob ()); + table = hb_blob_get_empty (); + } + } + ~accelerator_t () { table.destroy (); } + + hb_blob_ptr_t table; + }; + + void collect_variation_indices (hb_collect_variation_indices_context_t *c) const + { get_lig_caret_list ().collect_variation_indices (c); } + + void remap_layout_variation_indices (const hb_set_t *layout_variation_indices, + hb_hashmap_t> *layout_variation_idx_delta_map /* OUT */) const + { + if (!has_var_store ()) return; + if (layout_variation_indices->is_empty ()) return; + + unsigned new_major = 0, new_minor = 0; + unsigned last_major = (layout_variation_indices->get_min ()) >> 16; + for (unsigned idx : layout_variation_indices->iter ()) + { + uint16_t major = idx >> 16; + if (major >= get_var_store ().get_sub_table_count ()) break; + if (major != last_major) + { + new_minor = 0; + ++new_major; + } + + unsigned new_idx = (new_major << 16) + new_minor; + if (!layout_variation_idx_delta_map->has (idx)) + continue; + int delta = hb_second (layout_variation_idx_delta_map->get (idx)); + + layout_variation_idx_delta_map->set (idx, hb_pair_t (new_idx, delta)); + ++new_minor; + last_major = major; + } + } + + protected: + union { + FixedVersion<> version; /* Version identifier */ + GDEFVersion1_2 version1; +#ifndef HB_NO_BEYOND_64K + GDEFVersion1_2 version2; +#endif + } u; + public: + DEFINE_SIZE_MIN (4); +}; + +struct GDEF_accelerator_t : GDEF::accelerator_t { + GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {} +}; + +} /* namespace OT */ + + +#endif /* OT_LAYOUT_GDEF_GDEF_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh index bfe6b36afd3..49e76e77509 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Anchor.hh @@ -58,8 +58,7 @@ struct Anchor return_trace (bool (reinterpret_cast (u.format1.copy (c->serializer)))); } return_trace (bool (reinterpret_cast (u.format2.copy (c->serializer)))); - case 3: return_trace (bool (reinterpret_cast (u.format3.copy (c->serializer, - c->plan->layout_variation_idx_map)))); + case 3: return_trace (u.format3.subset (c)); default:return_trace (false); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh index d77b4699be9..e7e3c5c6d1e 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/AnchorFormat3.hh @@ -41,24 +41,54 @@ struct AnchorFormat3 *y += (this+yDeviceTable).get_y_delta (font, c->var_store, c->var_store_cache); } - AnchorFormat3* copy (hb_serialize_context_t *c, - const hb_map_t *layout_variation_idx_map) const + bool subset (hb_subset_context_t *c) const { - TRACE_SERIALIZE (this); - if (!layout_variation_idx_map) return_trace (nullptr); + TRACE_SUBSET (this); + auto *out = c->serializer->start_embed (*this); + if (unlikely (!out)) return_trace (false); + if (unlikely (!c->serializer->embed (format))) return_trace (false); + if (unlikely (!c->serializer->embed (xCoordinate))) return_trace (false); + if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false); - auto *out = c->embed (this); - if (unlikely (!out)) return_trace (nullptr); + unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; + if (c->plan->layout_variation_idx_delta_map.has (x_varidx)) + { + int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (x_varidx)); + if (delta != 0) + { + if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta, + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } + } - out->xDeviceTable.serialize_copy (c, xDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map); - out->yDeviceTable.serialize_copy (c, yDeviceTable, this, 0, hb_serialize_context_t::Head, layout_variation_idx_map); + unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX; + if (c->plan->layout_variation_idx_delta_map.has (y_varidx)) + { + int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (y_varidx)); + if (delta != 0) + { + if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta, + HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return_trace (false); + } + } + + if (c->plan->all_axes_pinned) + return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW)); + + if (!c->serializer->embed (xDeviceTable)) return_trace (false); + if (!c->serializer->embed (yDeviceTable)) return_trace (false); + + out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map); + out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map); return_trace (out); } void collect_variation_indices (hb_collect_variation_indices_context_t *c) const { - (this+xDeviceTable).collect_variation_indices (c->layout_variation_indices); - (this+yDeviceTable).collect_variation_indices (c->layout_variation_indices); + (this+xDeviceTable).collect_variation_indices (c); + (this+yDeviceTable).collect_variation_indices (c); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Common.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Common.hh index e16c06729d2..408197454f1 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Common.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/Common.hh @@ -22,7 +22,8 @@ template static void SinglePos_serialize (hb_serialize_context_t *c, const SrcLookup *src, Iterator it, - const hb_map_t *layout_variation_idx_map); + const hb_hashmap_t> *layout_variation_idx_delta_map, + bool all_axes_pinned); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh index c105cfb0916..0105a9b8542 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePos.hh @@ -19,8 +19,8 @@ struct CursivePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); default:return_trace (c->default_return_value ()); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh index e212fab976b..13a435d00bf 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/CursivePosFormat1.hh @@ -140,7 +140,14 @@ struct CursivePosFormat1 unsigned int i = skippy_iter.idx; unsigned int j = buffer->idx; - buffer->unsafe_to_break (i, j); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "cursive attaching glyph at %u to glyph at %u", + i, j); + } + + buffer->unsafe_to_break (i, j + 1); float entry_x, entry_y, exit_x, exit_y; (this+prev_record.exitAnchor).get_anchor (c, buffer->info[i].codepoint, &exit_x, &exit_y); (this+this_record.entryAnchor).get_anchor (c, buffer->info[j].codepoint, &entry_x, &entry_y); @@ -223,7 +230,20 @@ struct CursivePosFormat1 * https://github.com/harfbuzz/harfbuzz/issues/2469 */ if (unlikely (pos[parent].attach_chain() == -pos[child].attach_chain())) + { pos[parent].attach_chain() = 0; + if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction))) + pos[parent].y_offset = 0; + else + pos[parent].x_offset = 0; + } + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "cursive attached glyph at %u to glyph at %u", + i, j); + } buffer->idx++; return_trace (true); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh similarity index 84% rename from src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS.hh rename to src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh index 224d6b746bd..9493ec987e8 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/GPOS.hh @@ -1,12 +1,15 @@ -#ifndef OT_LAYOUT_GPOS_HH -#define OT_LAYOUT_GPOS_HH +#ifndef OT_LAYOUT_GPOS_GPOS_HH +#define OT_LAYOUT_GPOS_GPOS_HH -#include "../../hb-ot-layout-common.hh" -#include "../../hb-ot-layout-gsubgpos.hh" -#include "GPOS/Common.hh" -#include "GPOS/PosLookup.hh" +#include "../../../hb-ot-layout-common.hh" +#include "../../../hb-ot-layout-gsubgpos.hh" +#include "Common.hh" +#include "PosLookup.hh" namespace OT { + +using Layout::GPOS_impl::PosLookup; + namespace Layout { static void @@ -25,10 +28,10 @@ struct GPOS : GSUBGPOS { static constexpr hb_tag_t tableTag = HB_OT_TAG_GPOS; - using Lookup = GPOS_impl::PosLookup; + using Lookup = PosLookup; - const GPOS_impl::PosLookup& get_lookup (unsigned int i) const - { return static_cast (GSUBGPOS::get_lookup (i)); } + const PosLookup& get_lookup (unsigned int i) const + { return static_cast (GSUBGPOS::get_lookup (i)); } static inline void position_start (hb_font_t *font, hb_buffer_t *buffer); static inline void position_finish_advances (hb_font_t *font, hb_buffer_t *buffer); @@ -36,12 +39,15 @@ struct GPOS : GSUBGPOS bool subset (hb_subset_context_t *c) const { - hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features); - return GSUBGPOS::subset (&l); + hb_subset_layout_context_t l (c, tableTag); + return GSUBGPOS::subset (&l); } bool sanitize (hb_sanitize_context_t *c) const - { return GSUBGPOS::sanitize (c); } + { + TRACE_SANITIZE (this); + return_trace (GSUBGPOS::sanitize (c)); + } HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, hb_face_t *face) const; @@ -51,7 +57,7 @@ struct GPOS : GSUBGPOS for (unsigned i = 0; i < GSUBGPOS::get_lookup_count (); i++) { if (!c->gpos_lookups->has (i)) continue; - const GPOS_impl::PosLookup &l = get_lookup (i); + const PosLookup &l = get_lookup (i); l.dispatch (c); } } @@ -59,7 +65,7 @@ struct GPOS : GSUBGPOS void closure_lookups (hb_face_t *face, const hb_set_t *glyphs, hb_set_t *lookup_indexes /* IN/OUT */) const - { GSUBGPOS::closure_lookups (face, glyphs, lookup_indexes); } + { GSUBGPOS::closure_lookups (face, glyphs, lookup_indexes); } typedef GSUBGPOS::accelerator_t accelerator_t; }; @@ -162,4 +168,4 @@ struct GPOS_accelerator_t : Layout::GPOS::accelerator_t { } -#endif /* OT_LAYOUT_GPOS_HH */ +#endif /* OT_LAYOUT_GPOS_GPOS_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh new file mode 100644 index 00000000000..a2d807cc320 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/LigatureArray.hh @@ -0,0 +1,56 @@ +#ifndef OT_LAYOUT_GPOS_LIGATUREARRAY_HH +#define OT_LAYOUT_GPOS_LIGATUREARRAY_HH + +namespace OT { +namespace Layout { +namespace GPOS_impl { + + +typedef AnchorMatrix LigatureAttach; /* component-major-- + * in order of writing direction--, + * mark-minor-- + * ordered by class--zero-based. */ + +/* Array of LigatureAttach tables ordered by LigatureCoverage Index */ +struct LigatureArray : List16OfOffset16To +{ + template + bool subset (hb_subset_context_t *c, + Iterator coverage, + unsigned class_count, + const hb_map_t *klass_mapping) const + { + TRACE_SUBSET (this); + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + + auto *out = c->serializer->start_embed (this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + + for (const auto _ : + hb_zip (coverage, *this) + | hb_filter (glyphset, hb_first)) + { + auto *matrix = out->serialize_append (c->serializer); + if (unlikely (!matrix)) return_trace (false); + + const LigatureAttach& src = (this + _.second); + auto indexes = + + hb_range (src.rows * class_count) + | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); }) + ; + matrix->serialize_subset (c, + _.second, + this, + src.rows, + indexes); + } + return_trace (this->len); + } +}; + + +} +} +} + +#endif /* OT_LAYOUT_GPOS_LIGATUREARRAY_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh index f8cddd19918..e80c05cd270 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkArray.hh @@ -39,6 +39,13 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y); glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "attaching mark glyph at %u to glyph at %u", + c->buffer->idx, glyph_pos); + } + hb_glyph_position_t &o = buffer->cur_pos(); o.x_offset = roundf (base_x - mark_x); o.y_offset = roundf (base_y - mark_y); @@ -46,6 +53,13 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove o.attach_chain() = (int) glyph_pos - (int) buffer->idx; buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT; + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "attached mark glyph at %u to glyph at %u", + c->buffer->idx, glyph_pos); + } + buffer->idx++; return_trace (true); } @@ -83,10 +97,11 @@ struct MarkArray : Array16Of /* Array of MarkRecords--in Cove } }; -static void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, - const MarkArray &mark_array, - const hb_set_t &glyphset, - hb_map_t* klass_mapping /* INOUT */) +HB_INTERNAL inline +void Markclass_closure_and_remap_indexes (const Coverage &mark_coverage, + const MarkArray &mark_array, + const hb_set_t &glyphset, + hb_map_t* klass_mapping /* INOUT */) { hb_set_t orig_classes; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh index e99e13ff84f..b1d1118a86b 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePos.hh @@ -11,18 +11,24 @@ struct MarkBasePos { protected: union { - HBUINT16 format; /* Format identifier */ - MarkBasePosFormat1 format1; + HBUINT16 format; /* Format identifier */ + MarkBasePosFormat1_2 format1; +#ifndef HB_NO_BEYOND_64K + MarkBasePosFormat1_2 format2; +#endif } u; public: template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh index a10b806fe5f..bf129a4a0e9 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkBasePosFormat1.hh @@ -12,26 +12,27 @@ typedef AnchorMatrix BaseArray; /* base-major-- * mark-minor-- * ordered by class--zero-based. */ -struct MarkBasePosFormat1 +template +struct MarkBasePosFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To + typename Types::template OffsetTo markCoverage; /* Offset to MarkCoverage table--from * beginning of MarkBasePos subtable */ - Offset16To + typename Types::template OffsetTo baseCoverage; /* Offset to BaseCoverage table--from * beginning of MarkBasePos subtable */ HBUINT16 classCount; /* Number of classes defined for marks */ - Offset16To + typename Types::template OffsetTo markArray; /* Offset to MarkArray table--from * beginning of MarkBasePos subtable */ - Offset16To + typename Types::template OffsetTo baseArray; /* Offset to BaseArray table--from * beginning of MarkBasePos subtable */ public: - DEFINE_SIZE_STATIC (12); + DEFINE_SIZE_STATIC (4 + 4 * Types::size); bool sanitize (hb_sanitize_context_t *c) const { @@ -89,6 +90,25 @@ struct MarkBasePosFormat1 const Coverage &get_coverage () const { return this+markCoverage; } + static inline bool accept (hb_buffer_t *buffer, unsigned idx) + { + /* We only want to attach to the first of a MultipleSubst sequence. + * https://github.com/harfbuzz/harfbuzz/issues/740 + * Reject others... + * ...but stop if we find a mark in the MultipleSubst sequence: + * https://github.com/harfbuzz/harfbuzz/issues/1020 */ + return !_hb_glyph_info_multiplied (&buffer->info[idx]) || + 0 == _hb_glyph_info_get_lig_comp (&buffer->info[idx]) || + (idx == 0 || + _hb_glyph_info_is_mark (&buffer->info[idx - 1]) || + !_hb_glyph_info_multiplied (&buffer->info[idx - 1]) || + _hb_glyph_info_get_lig_id (&buffer->info[idx]) != + _hb_glyph_info_get_lig_id (&buffer->info[idx - 1]) || + _hb_glyph_info_get_lig_comp (&buffer->info[idx]) != + _hb_glyph_info_get_lig_comp (&buffer->info[idx - 1]) + 1 + ); + } + bool apply (hb_ot_apply_context_t *c) const { TRACE_APPLY (this); @@ -96,47 +116,54 @@ struct MarkBasePosFormat1 unsigned int mark_index = (this+markCoverage).get_coverage (buffer->cur().codepoint); if (likely (mark_index == NOT_COVERED)) return_trace (false); - /* Now we search backwards for a non-mark glyph */ + /* Now we search backwards for a non-mark glyph. + * We don't use skippy_iter.prev() to avoid O(n^2) behavior. */ + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - do { - unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) + + if (c->last_base_until > buffer->idx) + { + c->last_base_until = 0; + c->last_base = -1; + } + unsigned j; + for (j = buffer->idx; j > c->last_base_until; j--) + { + auto match = skippy_iter.match (buffer->info[j - 1]); + if (match == skippy_iter.MATCH) { - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); - return_trace (false); + // https://github.com/harfbuzz/harfbuzz/issues/4124 + if (!accept (buffer, j - 1) && + NOT_COVERED == (this+baseCoverage).get_coverage (buffer->info[j - 1].codepoint)) + match = skippy_iter.SKIP; } - - /* We only want to attach to the first of a MultipleSubst sequence. - * https://github.com/harfbuzz/harfbuzz/issues/740 - * Reject others... - * ...but stop if we find a mark in the MultipleSubst sequence: - * https://github.com/harfbuzz/harfbuzz/issues/1020 */ - if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) || - 0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) || - (skippy_iter.idx == 0 || - _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) || - _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) != - _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) || - _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) != - _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1 - )) + if (match == skippy_iter.MATCH) + { + c->last_base = (signed) j - 1; break; - skippy_iter.reject (); - } while (true); + } + } + c->last_base_until = buffer->idx; + if (c->last_base == -1) + { + buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1); + return_trace (false); + } + + unsigned idx = (unsigned) c->last_base; /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */ - //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } + //if (!_hb_glyph_info_is_base_glyph (&buffer->info[idx])) { return_trace (false); } - unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); + unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[idx].codepoint); if (base_index == NOT_COVERED) { - buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1); return_trace (false); } - return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); + return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx)); } bool subset (hb_subset_context_t *c) const diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh index 7e74aa73e0a..b10102880c0 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPos.hh @@ -11,18 +11,24 @@ struct MarkLigPos { protected: union { - HBUINT16 format; /* Format identifier */ - MarkLigPosFormat1 format1; + HBUINT16 format; /* Format identifier */ + MarkLigPosFormat1_2 format1; +#ifndef HB_NO_BEYOND_64K + MarkLigPosFormat1_2 format2; +#endif } u; public: template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh index 4382aa6c6cb..4accd8166ba 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkLigPosFormat1.hh @@ -1,72 +1,34 @@ #ifndef OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH #define OT_LAYOUT_GPOS_MARKLIGPOSFORMAT1_HH +#include "LigatureArray.hh" + namespace OT { namespace Layout { namespace GPOS_impl { -typedef AnchorMatrix LigatureAttach; /* component-major-- - * in order of writing direction--, - * mark-minor-- - * ordered by class--zero-based. */ -/* Array of LigatureAttach tables ordered by LigatureCoverage Index */ -struct LigatureArray : List16OfOffset16To -{ - template - bool subset (hb_subset_context_t *c, - Iterator coverage, - unsigned class_count, - const hb_map_t *klass_mapping) const - { - TRACE_SUBSET (this); - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - - auto *out = c->serializer->start_embed (this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - - for (const auto _ : + hb_zip (coverage, *this) - | hb_filter (glyphset, hb_first)) - { - auto *matrix = out->serialize_append (c->serializer); - if (unlikely (!matrix)) return_trace (false); - - const LigatureAttach& src = (this + _.second); - auto indexes = - + hb_range (src.rows * class_count) - | hb_filter ([=] (unsigned index) { return klass_mapping->has (index % class_count); }) - ; - matrix->serialize_subset (c, - _.second, - this, - src.rows, - indexes); - } - return_trace (this->len); - } -}; - -struct MarkLigPosFormat1 +template +struct MarkLigPosFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To + typename Types::template OffsetTo markCoverage; /* Offset to Mark Coverage table--from * beginning of MarkLigPos subtable */ - Offset16To + typename Types::template OffsetTo ligatureCoverage; /* Offset to Ligature Coverage * table--from beginning of MarkLigPos * subtable */ HBUINT16 classCount; /* Number of defined mark classes */ - Offset16To + typename Types::template OffsetTo markArray; /* Offset to MarkArray table--from * beginning of MarkLigPos subtable */ - Offset16To + typename Types::template OffsetTo ligatureArray; /* Offset to LigatureArray table--from * beginning of MarkLigPos subtable */ public: - DEFINE_SIZE_STATIC (12); + DEFINE_SIZE_STATIC (4 + 4 * Types::size); bool sanitize (hb_sanitize_context_t *c) const { @@ -138,20 +100,37 @@ struct MarkLigPosFormat1 if (likely (mark_index == NOT_COVERED)) return_trace (false); /* Now we search backwards for a non-mark glyph */ + hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; - skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - unsigned unsafe_from; - if (!skippy_iter.prev (&unsafe_from)) + + if (c->last_base_until > buffer->idx) + { + c->last_base_until = 0; + c->last_base = -1; + } + unsigned j; + for (j = buffer->idx; j > c->last_base_until; j--) { - buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + auto match = skippy_iter.match (buffer->info[j - 1]); + if (match == skippy_iter.MATCH) + { + c->last_base = (signed) j - 1; + break; + } + } + c->last_base_until = buffer->idx; + if (c->last_base == -1) + { + buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1); return_trace (false); } + j = (unsigned) c->last_base; + /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ - //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); } + //if (!_hb_glyph_info_is_ligature (&buffer->info[j])) { return_trace (false); } - unsigned int j = skippy_iter.idx; unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); if (lig_index == NOT_COVERED) { diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh index c0eee6d54cf..e0d9eca0280 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPos.hh @@ -11,18 +11,24 @@ struct MarkMarkPos { protected: union { - HBUINT16 format; /* Format identifier */ - MarkMarkPosFormat1 format1; + HBUINT16 format; /* Format identifier */ + MarkMarkPosFormat1_2 format1; +#ifndef HB_NO_BEYOND_64K + MarkMarkPosFormat1_2 format2; +#endif } u; public: template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh index c48a74f7738..fbcebb80441 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkMarkPosFormat1.hh @@ -12,27 +12,28 @@ typedef AnchorMatrix Mark2Array; /* mark2-major-- * mark1-minor-- * ordered by class--zero-based. */ -struct MarkMarkPosFormat1 +template +struct MarkMarkPosFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To + typename Types::template OffsetTo mark1Coverage; /* Offset to Combining Mark1 Coverage * table--from beginning of MarkMarkPos * subtable */ - Offset16To + typename Types::template OffsetTo mark2Coverage; /* Offset to Combining Mark2 Coverage * table--from beginning of MarkMarkPos * subtable */ HBUINT16 classCount; /* Number of defined mark classes */ - Offset16To + typename Types::template OffsetTo mark1Array; /* Offset to Mark1Array table--from * beginning of MarkMarkPos subtable */ - Offset16To + typename Types::template OffsetTo mark2Array; /* Offset to Mark2Array table--from * beginning of MarkMarkPos subtable */ public: - DEFINE_SIZE_STATIC (12); + DEFINE_SIZE_STATIC (4 + 4 * Types::size); bool sanitize (hb_sanitize_context_t *c) const { @@ -100,7 +101,7 @@ struct MarkMarkPosFormat1 /* now we search backwards for a suitable mark glyph until a non-mark glyph */ hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); + skippy_iter.set_lookup_props (c->lookup_props & ~(uint32_t)LookupFlag::IgnoreFlags); unsigned unsafe_from; if (!skippy_iter.prev (&unsafe_from)) { diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh index 7a514453aee..a7d489d2a51 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/MarkRecord.hh @@ -9,7 +9,7 @@ struct MarkRecord { friend struct MarkArray; - protected: + public: HBUINT16 klass; /* Class defined for this mark */ Offset16To markAnchor; /* Offset to Anchor table--from diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh index 8479178d384..e3794ea9ed5 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPos.hh @@ -12,20 +12,28 @@ struct PairPos { protected: union { - HBUINT16 format; /* Format identifier */ - PairPosFormat1 format1; - PairPosFormat2 format2; + HBUINT16 format; /* Format identifier */ + PairPosFormat1_3 format1; + PairPosFormat2_4 format2; +#ifndef HB_NO_BEYOND_64K + PairPosFormat1_3 format3; + PairPosFormat2_4 format4; +#endif } u; public: template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); + case 4: return_trace (c->dispatch (u.format4, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh index 35a2db2d45e..ec9475d113f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat1.hh @@ -1,248 +1,22 @@ #ifndef OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH #define OT_LAYOUT_GPOS_PAIRPOSFORMAT1_HH +#include "PairSet.hh" + namespace OT { namespace Layout { namespace GPOS_impl { -struct PairValueRecord -{ - friend struct PairSet; - - int cmp (hb_codepoint_t k) const - { return secondGlyph.cmp (k); } - - struct context_t - { - const void *base; - const ValueFormat *valueFormats; - const ValueFormat *newFormats; - unsigned len1; /* valueFormats[0].get_len() */ - const hb_map_t *glyph_map; - const hb_map_t *layout_variation_idx_map; - }; - - bool subset (hb_subset_context_t *c, - context_t *closure) const - { - TRACE_SERIALIZE (this); - auto *s = c->serializer; - auto *out = s->start_embed (*this); - if (unlikely (!s->extend_min (out))) return_trace (false); - - out->secondGlyph = (*closure->glyph_map)[secondGlyph]; - - closure->valueFormats[0].copy_values (s, - closure->newFormats[0], - closure->base, &values[0], - closure->layout_variation_idx_map); - closure->valueFormats[1].copy_values (s, - closure->newFormats[1], - closure->base, - &values[closure->len1], - closure->layout_variation_idx_map); - - return_trace (true); - } - - void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const ValueFormat *valueFormats, - const void *base) const - { - unsigned record1_len = valueFormats[0].get_len (); - unsigned record2_len = valueFormats[1].get_len (); - const hb_array_t values_array = values.as_array (record1_len + record2_len); - - if (valueFormats[0].has_device ()) - valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len)); - - if (valueFormats[1].has_device ()) - valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len)); - } - - bool intersects (const hb_set_t& glyphset) const - { - return glyphset.has(secondGlyph); - } - - const Value* get_values_1 () const - { - return &values[0]; - } - - const Value* get_values_2 (ValueFormat format1) const - { - return &values[format1.get_len ()]; - } - - protected: - HBGlyphID16 secondGlyph; /* GlyphID of second glyph in the - * pair--first glyph is listed in the - * Coverage table */ - ValueRecord values; /* Positioning data for the first glyph - * followed by for second glyph */ - public: - DEFINE_SIZE_ARRAY (2, values); -}; -struct PairSet +template +struct PairPosFormat1_3 { - friend struct PairPosFormat1; - - bool intersects (const hb_set_t *glyphs, - const ValueFormat *valueFormats) const - { - unsigned int len1 = valueFormats[0].get_len (); - unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - - const PairValueRecord *record = &firstPairValueRecord; - unsigned int count = len; - for (unsigned int i = 0; i < count; i++) - { - if (glyphs->has (record->secondGlyph)) - return true; - record = &StructAtOffset (record, record_size); - } - return false; - } - - void collect_glyphs (hb_collect_glyphs_context_t *c, - const ValueFormat *valueFormats) const - { - unsigned int len1 = valueFormats[0].get_len (); - unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - - const PairValueRecord *record = &firstPairValueRecord; - c->input->add_array (&record->secondGlyph, len, record_size); - } - - void collect_variation_indices (hb_collect_variation_indices_context_t *c, - const ValueFormat *valueFormats) const - { - unsigned len1 = valueFormats[0].get_len (); - unsigned len2 = valueFormats[1].get_len (); - unsigned record_size = HBUINT16::static_size * (1 + len1 + len2); - - const PairValueRecord *record = &firstPairValueRecord; - unsigned count = len; - for (unsigned i = 0; i < count; i++) - { - if (c->glyph_set->has (record->secondGlyph)) - { record->collect_variation_indices (c, valueFormats, this); } - - record = &StructAtOffset (record, record_size); - } - } - - bool apply (hb_ot_apply_context_t *c, - const ValueFormat *valueFormats, - unsigned int pos) const - { - TRACE_APPLY (this); - hb_buffer_t *buffer = c->buffer; - unsigned int len1 = valueFormats[0].get_len (); - unsigned int len2 = valueFormats[1].get_len (); - unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2); - - const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, - &firstPairValueRecord, - len, - record_size); - if (record) - { - bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); - bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); - if (applied_first || applied_second) - buffer->unsafe_to_break (buffer->idx, pos + 1); - if (len2) - pos++; - buffer->idx = pos; - return_trace (true); - } - buffer->unsafe_to_concat (buffer->idx, pos + 1); - return_trace (false); - } - - bool subset (hb_subset_context_t *c, - const ValueFormat valueFormats[2], - const ValueFormat newFormats[2]) const - { - TRACE_SUBSET (this); - auto snap = c->serializer->snapshot (); - - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - out->len = 0; - - const hb_set_t &glyphset = *c->plan->glyphset_gsub (); - const hb_map_t &glyph_map = *c->plan->glyph_map; - - unsigned len1 = valueFormats[0].get_len (); - unsigned len2 = valueFormats[1].get_len (); - unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); - - PairValueRecord::context_t context = - { - this, - valueFormats, - newFormats, - len1, - &glyph_map, - c->plan->layout_variation_idx_map - }; - - const PairValueRecord *record = &firstPairValueRecord; - unsigned count = len, num = 0; - for (unsigned i = 0; i < count; i++) - { - if (glyphset.has (record->secondGlyph) - && record->subset (c, &context)) num++; - record = &StructAtOffset (record, record_size); - } - - out->len = num; - if (!num) c->serializer->revert (snap); - return_trace (num); - } - - struct sanitize_closure_t - { - const ValueFormat *valueFormats; - unsigned int len1; /* valueFormats[0].get_len() */ - unsigned int stride; /* 1 + len1 + len2 */ - }; - - bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const - { - TRACE_SANITIZE (this); - if (!(c->check_struct (this) - && c->check_range (&firstPairValueRecord, - len, - HBUINT16::static_size, - closure->stride))) return_trace (false); - - unsigned int count = len; - const PairValueRecord *record = &firstPairValueRecord; - return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && - closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)); - } + using PairSet = GPOS_impl::PairSet; + using PairValueRecord = GPOS_impl::PairValueRecord; - protected: - HBUINT16 len; /* Number of PairValueRecords */ - PairValueRecord firstPairValueRecord; - /* Array of PairValueRecords--ordered - * by GlyphID of the second glyph */ - public: - DEFINE_SIZE_MIN (2); -}; - -struct PairPosFormat1 -{ protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To + typename Types::template OffsetTo coverage; /* Offset to Coverage table--from * beginning of subtable */ ValueFormat valueFormat[2]; /* [0] Defines the types of data in @@ -251,11 +25,11 @@ struct PairPosFormat1 /* [1] Defines the types of data in * ValueRecord2--for the second glyph * in the pair--may be zero (0) */ - Array16OfOffset16To + Array16Of> pairSet; /* Array of PairSet tables * ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (10, pairSet); + DEFINE_SIZE_ARRAY (8 + Types::size, pairSet); bool sanitize (hb_sanitize_context_t *c) const { @@ -265,24 +39,36 @@ struct PairPosFormat1 unsigned int len1 = valueFormat[0].get_len (); unsigned int len2 = valueFormat[1].get_len (); - PairSet::sanitize_closure_t closure = + typename PairSet::sanitize_closure_t closure = { valueFormat, len1, - 1 + len1 + len2 + PairSet::get_size (len1, len2) }; return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure)); } - bool intersects (const hb_set_t *glyphs) const { + auto &cov = this+coverage; + + if (pairSet.len > glyphs->get_population () * hb_bit_storage ((unsigned) pairSet.len) / 4) + { + for (hb_codepoint_t g = HB_SET_VALUE_INVALID; glyphs->next (&g);) + { + unsigned i = cov.get_coverage (g); + if ((this+pairSet[i]).intersects (glyphs, valueFormat)) + return true; + } + return false; + } + return - + hb_zip (this+coverage, pairSet) + + hb_zip (cov, pairSet) | hb_filter (*glyphs, hb_first) | hb_map (hb_second) - | hb_map ([glyphs, this] (const Offset16To &_) + | hb_map ([glyphs, this] (const typename Types::template OffsetTo &_) { return (this+_).intersects (glyphs, valueFormat); }) | hb_any ; @@ -354,11 +140,17 @@ struct PairPosFormat1 out->valueFormat[1] = newFormats.second; } + if (c->plan->all_axes_pinned) + { + out->valueFormat[0] = out->valueFormat[0].drop_device_table_flags (); + out->valueFormat[1] = out->valueFormat[1].drop_device_table_flags (); + } + hb_sorted_vector_t new_coverage; + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) - | hb_filter ([this, c, out] (const Offset16To& _) + | hb_filter ([this, c, out] (const typename Types::template OffsetTo& _) { auto snap = c->serializer->snapshot (); auto *o = out->pairSet.serialize_append (c->serializer); @@ -385,19 +177,21 @@ struct PairPosFormat1 hb_pair_t compute_effective_value_formats (const hb_set_t& glyphset) const { - unsigned len1 = valueFormat[0].get_len (); - unsigned len2 = valueFormat[1].get_len (); - unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2); + unsigned record_size = PairSet::get_size (valueFormat); unsigned format1 = 0; unsigned format2 = 0; - for (const Offset16To& _ : - + hb_zip (this+coverage, pairSet) | hb_filter (glyphset, hb_first) | hb_map (hb_second)) + for (const auto & _ : + + hb_zip (this+coverage, pairSet) + | hb_filter (glyphset, hb_first) + | hb_map (hb_second) + ) { const PairSet& set = (this + _); const PairValueRecord *record = &set.firstPairValueRecord; - for (unsigned i = 0; i < set.len; i++) + unsigned count = set.len; + for (unsigned i = 0; i < count; i++) { if (record->intersects (glyphset)) { @@ -406,6 +200,9 @@ struct PairPosFormat1 } record = &StructAtOffset (record, record_size); } + + if (format1 == valueFormat[0] && format2 == valueFormat[1]) + break; } return hb_pair (format1, format2); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh index 3f5f9959c46..17486dddaf7 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairPosFormat2.hh @@ -7,11 +7,12 @@ namespace OT { namespace Layout { namespace GPOS_impl { -struct PairPosFormat2 +template +struct PairPosFormat2_4 { protected: HBUINT16 format; /* Format identifier--format = 2 */ - Offset16To + typename Types::template OffsetTo coverage; /* Offset to Coverage table--from * beginning of subtable */ ValueFormat valueFormat1; /* ValueRecord definition--for the @@ -20,11 +21,11 @@ struct PairPosFormat2 ValueFormat valueFormat2; /* ValueRecord definition--for the * second glyph of the pair--may be * zero (0) */ - Offset16To + typename Types::template OffsetTo classDef1; /* Offset to ClassDef table--from * beginning of PairPos subtable--for * the first glyph of the pair */ - Offset16To + typename Types::template OffsetTo classDef2; /* Offset to ClassDef table--from * beginning of PairPos subtable--for * the second glyph of the pair */ @@ -36,7 +37,7 @@ struct PairPosFormat2 * class1-major, class2-minor, * Each entry has value1 and value2 */ public: - DEFINE_SIZE_ARRAY (16, values); + DEFINE_SIZE_ARRAY (10 + 3 * Types::size, values); bool sanitize (hb_sanitize_context_t *c) const { @@ -48,7 +49,7 @@ struct PairPosFormat2 unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); - unsigned int stride = len1 + len2; + unsigned int stride = HBUINT16::static_size * (len1 + len2); unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size (); unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count; return_trace (c->check_range ((const void *) values, @@ -216,10 +217,31 @@ struct PairPosFormat2 } bail: + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "try kerning glyphs at %u,%u", + c->buffer->idx, skippy_iter.idx); + } applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + if (applied_first || applied_second) + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "kerned glyphs at %u,%u", + c->buffer->idx, skippy_iter.idx); + } + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "tried kerning glyphs at %u,%u", + c->buffer->idx, skippy_iter.idx); + } + success: if (applied_first || applied_second) buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); @@ -227,10 +249,15 @@ struct PairPosFormat2 boring: buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + if (len2) + { + skippy_iter.idx++; + // https://github.com/harfbuzz/harfbuzz/issues/3824 + // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116 + buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); + } buffer->idx = skippy_iter.idx; - if (len2) - buffer->idx++; return_trace (true); } @@ -260,13 +287,19 @@ struct PairPosFormat2 out->valueFormat1 = newFormats.first; out->valueFormat2 = newFormats.second; + if (c->plan->all_axes_pinned) + { + out->valueFormat1 = out->valueFormat1.drop_device_table_flags (); + out->valueFormat2 = out->valueFormat2.drop_device_table_flags (); + } + for (unsigned class1_idx : + hb_range ((unsigned) class1Count) | hb_filter (klass1_map)) { for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) { unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); - valueFormat1.copy_values (c->serializer, newFormats.first, this, &values[idx], c->plan->layout_variation_idx_map); - valueFormat2.copy_values (c->serializer, newFormats.second, this, &values[idx + len1], c->plan->layout_variation_idx_map); + valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map); + valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map); } } @@ -289,6 +322,7 @@ struct PairPosFormat2 { unsigned len1 = valueFormat1.get_len (); unsigned len2 = valueFormat2.get_len (); + unsigned record_size = len1 + len2; unsigned format1 = 0; unsigned format2 = 0; @@ -297,10 +331,13 @@ struct PairPosFormat2 { for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map)) { - unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2); + unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * record_size; format1 = format1 | valueFormat1.get_effective_format (&values[idx]); format2 = format2 | valueFormat2.get_effective_format (&values[idx + len1]); } + + if (format1 == valueFormat1 && format2 == valueFormat2) + break; } return hb_pair (format1, format2); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh new file mode 100644 index 00000000000..adeb08e910b --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairSet.hh @@ -0,0 +1,207 @@ +#ifndef OT_LAYOUT_GPOS_PAIRSET_HH +#define OT_LAYOUT_GPOS_PAIRSET_HH + +#include "PairValueRecord.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + + +template +struct PairSet +{ + template + friend struct PairPosFormat1_3; + + using PairValueRecord = GPOS_impl::PairValueRecord; + + protected: + HBUINT16 len; /* Number of PairValueRecords */ + PairValueRecord firstPairValueRecord; + /* Array of PairValueRecords--ordered + * by GlyphID of the second glyph */ + public: + DEFINE_SIZE_MIN (2); + + static unsigned get_size (unsigned len1, unsigned len2) + { + return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2); + } + static unsigned get_size (const ValueFormat valueFormats[2]) + { + unsigned len1 = valueFormats[0].get_len (); + unsigned len2 = valueFormats[1].get_len (); + return get_size (len1, len2); + } + + struct sanitize_closure_t + { + const ValueFormat *valueFormats; + unsigned int len1; /* valueFormats[0].get_len() */ + unsigned int stride; /* bytes */ + }; + + bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const + { + TRACE_SANITIZE (this); + if (!(c->check_struct (this) + && c->check_range (&firstPairValueRecord, + len, + closure->stride))) return_trace (false); + + unsigned int count = len; + const PairValueRecord *record = &firstPairValueRecord; + return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, this, &record->values[0], count, closure->stride) && + closure->valueFormats[1].sanitize_values_stride_unsafe (c, this, &record->values[closure->len1], count, closure->stride)); + } + + bool intersects (const hb_set_t *glyphs, + const ValueFormat *valueFormats) const + { + unsigned record_size = get_size (valueFormats); + + const PairValueRecord *record = &firstPairValueRecord; + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + { + if (glyphs->has (record->secondGlyph)) + return true; + record = &StructAtOffset (record, record_size); + } + return false; + } + + void collect_glyphs (hb_collect_glyphs_context_t *c, + const ValueFormat *valueFormats) const + { + unsigned record_size = get_size (valueFormats); + + const PairValueRecord *record = &firstPairValueRecord; + c->input->add_array (&record->secondGlyph, len, record_size); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueFormat *valueFormats) const + { + unsigned record_size = get_size (valueFormats); + + const PairValueRecord *record = &firstPairValueRecord; + unsigned count = len; + for (unsigned i = 0; i < count; i++) + { + if (c->glyph_set->has (record->secondGlyph)) + { record->collect_variation_indices (c, valueFormats, this); } + + record = &StructAtOffset (record, record_size); + } + } + + bool apply (hb_ot_apply_context_t *c, + const ValueFormat *valueFormats, + unsigned int pos) const + { + TRACE_APPLY (this); + hb_buffer_t *buffer = c->buffer; + unsigned int len1 = valueFormats[0].get_len (); + unsigned int len2 = valueFormats[1].get_len (); + unsigned record_size = get_size (len1, len2); + + const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint, + &firstPairValueRecord, + len, + record_size); + if (record) + { + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "try kerning glyphs at %u,%u", + c->buffer->idx, pos); + } + + bool applied_first = valueFormats[0].apply_value (c, this, &record->values[0], buffer->cur_pos()); + bool applied_second = valueFormats[1].apply_value (c, this, &record->values[len1], buffer->pos[pos]); + + if (applied_first || applied_second) + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "kerned glyphs at %u,%u", + c->buffer->idx, pos); + } + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "tried kerning glyphs at %u,%u", + c->buffer->idx, pos); + } + + if (applied_first || applied_second) + buffer->unsafe_to_break (buffer->idx, pos + 1); + + if (len2) + { + pos++; + // https://github.com/harfbuzz/harfbuzz/issues/3824 + // https://github.com/harfbuzz/harfbuzz/issues/3888#issuecomment-1326781116 + buffer->unsafe_to_break (buffer->idx, pos + 1); + } + + buffer->idx = pos; + return_trace (true); + } + buffer->unsafe_to_concat (buffer->idx, pos + 1); + return_trace (false); + } + + bool subset (hb_subset_context_t *c, + const ValueFormat valueFormats[2], + const ValueFormat newFormats[2]) const + { + TRACE_SUBSET (this); + auto snap = c->serializer->snapshot (); + + auto *out = c->serializer->start_embed (*this); + if (unlikely (!c->serializer->extend_min (out))) return_trace (false); + out->len = 0; + + const hb_set_t &glyphset = *c->plan->glyphset_gsub (); + const hb_map_t &glyph_map = *c->plan->glyph_map; + + unsigned len1 = valueFormats[0].get_len (); + unsigned len2 = valueFormats[1].get_len (); + unsigned record_size = get_size (len1, len2); + + typename PairValueRecord::context_t context = + { + this, + valueFormats, + newFormats, + len1, + &glyph_map, + &c->plan->layout_variation_idx_delta_map + }; + + const PairValueRecord *record = &firstPairValueRecord; + unsigned count = len, num = 0; + for (unsigned i = 0; i < count; i++) + { + if (glyphset.has (record->secondGlyph) + && record->subset (c, &context)) num++; + record = &StructAtOffset (record, record_size); + } + + out->len = num; + if (!num) c->serializer->revert (snap); + return_trace (num); + } +}; + + +} +} +} + +#endif // OT_LAYOUT_GPOS_PAIRSET_HH diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh new file mode 100644 index 00000000000..d4f549a480d --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/PairValueRecord.hh @@ -0,0 +1,99 @@ +#ifndef OT_LAYOUT_GPOS_PAIRVALUERECORD_HH +#define OT_LAYOUT_GPOS_PAIRVALUERECORD_HH + +#include "ValueFormat.hh" + +namespace OT { +namespace Layout { +namespace GPOS_impl { + + +template +struct PairValueRecord +{ + template + friend struct PairSet; + + protected: + typename Types::HBGlyphID + secondGlyph; /* GlyphID of second glyph in the + * pair--first glyph is listed in the + * Coverage table */ + ValueRecord values; /* Positioning data for the first glyph + * followed by for second glyph */ + public: + DEFINE_SIZE_ARRAY (Types::size, values); + + int cmp (hb_codepoint_t k) const + { return secondGlyph.cmp (k); } + + struct context_t + { + const void *base; + const ValueFormat *valueFormats; + const ValueFormat *newFormats; + unsigned len1; /* valueFormats[0].get_len() */ + const hb_map_t *glyph_map; + const hb_hashmap_t> *layout_variation_idx_delta_map; + }; + + bool subset (hb_subset_context_t *c, + context_t *closure) const + { + TRACE_SERIALIZE (this); + auto *s = c->serializer; + auto *out = s->start_embed (*this); + if (unlikely (!s->extend_min (out))) return_trace (false); + + out->secondGlyph = (*closure->glyph_map)[secondGlyph]; + + closure->valueFormats[0].copy_values (s, + closure->newFormats[0], + closure->base, &values[0], + closure->layout_variation_idx_delta_map); + closure->valueFormats[1].copy_values (s, + closure->newFormats[1], + closure->base, + &values[closure->len1], + closure->layout_variation_idx_delta_map); + + return_trace (true); + } + + void collect_variation_indices (hb_collect_variation_indices_context_t *c, + const ValueFormat *valueFormats, + const void *base) const + { + unsigned record1_len = valueFormats[0].get_len (); + unsigned record2_len = valueFormats[1].get_len (); + const hb_array_t values_array = values.as_array (record1_len + record2_len); + + if (valueFormats[0].has_device ()) + valueFormats[0].collect_variation_indices (c, base, values_array.sub_array (0, record1_len)); + + if (valueFormats[1].has_device ()) + valueFormats[1].collect_variation_indices (c, base, values_array.sub_array (record1_len, record2_len)); + } + + bool intersects (const hb_set_t& glyphset) const + { + return glyphset.has(secondGlyph); + } + + const Value* get_values_1 () const + { + return &values[0]; + } + + const Value* get_values_2 (ValueFormat format1) const + { + return &values[format1.get_len ()]; + } +}; + + +} +} +} + +#endif // OT_LAYOUT_GPOS_PAIRVALUERECORD_HH diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh index 57e146befd6..3af6c499659 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePos.hh @@ -38,17 +38,18 @@ struct SinglePos void serialize (hb_serialize_context_t *c, const SrcLookup* src, Iterator glyph_val_iter_pairs, - const hb_map_t *layout_variation_idx_map) + const hb_hashmap_t> *layout_variation_idx_delta_map, + bool all_axes_pinned) { if (unlikely (!c->extend_min (u.format))) return; unsigned format = 2; ValueFormat new_format = src->get_value_format (); + if (all_axes_pinned) + new_format = new_format.drop_device_table_flags (); + if (glyph_val_iter_pairs) - { format = get_format (glyph_val_iter_pairs); - new_format = src->get_value_format ().get_effective_format (+ glyph_val_iter_pairs | hb_map (hb_second)); - } u.format = format; switch (u.format) { @@ -56,13 +57,13 @@ struct SinglePos src, glyph_val_iter_pairs, new_format, - layout_variation_idx_map); + layout_variation_idx_delta_map); return; case 2: u.format2.serialize (c, src, glyph_val_iter_pairs, new_format, - layout_variation_idx_map); + layout_variation_idx_delta_map); return; default:return; } @@ -71,8 +72,8 @@ struct SinglePos template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); @@ -87,8 +88,9 @@ static void SinglePos_serialize (hb_serialize_context_t *c, const SrcLookup *src, Iterator it, - const hb_map_t *layout_variation_idx_map) -{ c->start_embed ()->serialize (c, src, it, layout_variation_idx_map); } + const hb_hashmap_t> *layout_variation_idx_delta_map, + bool all_axes_pinned) +{ c->start_embed ()->serialize (c, src, it, layout_variation_idx_delta_map, all_axes_pinned); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh index 8b7840ed0eb..53aff9f3dfc 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat1.hh @@ -39,12 +39,10 @@ struct SinglePosFormat1 { if (!valueFormat.has_device ()) return; - auto it = - + hb_iter (this+coverage) - | hb_filter (c->glyph_set) - ; + hb_set_t intersection; + (this+coverage).intersect_set (*c->glyph_set, intersection); + if (!intersection) return; - if (!it) return; valueFormat.collect_variation_indices (c, this, values.as_array (valueFormat.get_len ())); } @@ -62,12 +60,44 @@ struct SinglePosFormat1 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "positioning glyph at %u", + c->buffer->idx); + } + valueFormat.apply_value (c, this, values, buffer->cur_pos()); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "positioned glyph at %u", + c->buffer->idx); + } + buffer->idx++; return_trace (true); } + bool + position_single (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t gid, + hb_glyph_position_t &pos) const + { + unsigned int index = (this+coverage).get_coverage (gid); + if (likely (index == NOT_COVERED)) return false; + + /* This is ugly... */ + hb_buffer_t buffer; + buffer.props.direction = direction; + OT::hb_ot_apply_context_t c (1, font, &buffer); + + valueFormat.apply_value (&c, this, values, pos); + return true; + } + template @@ -75,7 +105,7 @@ struct SinglePosFormat1 const SrcLookup *src, Iterator it, ValueFormat newFormat, - const hb_map_t *layout_variation_idx_map) + const hb_hashmap_t> *layout_variation_idx_delta_map) { if (unlikely (!c->extend_min (this))) return; if (unlikely (!c->check_assign (valueFormat, @@ -84,7 +114,7 @@ struct SinglePosFormat1 for (const hb_array_t& _ : + it | hb_map (hb_second)) { - src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); + src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); // Only serialize the first entry in the iterator, the rest are assumed to // be the same. break; @@ -104,15 +134,17 @@ struct SinglePosFormat1 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); const hb_map_t &glyph_map = *c->plan->glyph_map; + hb_set_t intersection; + (this+coverage).intersect_set (glyphset, intersection); + auto it = - + hb_iter (this+coverage) - | hb_filter (glyphset) + + hb_iter (intersection) | hb_map_retains_sorting (glyph_map) | hb_zip (hb_repeat (values.as_array (valueFormat.get_len ()))) ; bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map); + SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); return_trace (ret); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh index 0d038b44220..6546eb16703 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/SinglePosFormat2.hh @@ -68,16 +68,52 @@ struct SinglePosFormat2 unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); - if (likely (index >= valueCount)) return_trace (false); + if (unlikely (index >= valueCount)) return_trace (false); + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "positioning glyph at %u", + c->buffer->idx); + } valueFormat.apply_value (c, this, &values[index * valueFormat.get_len ()], buffer->cur_pos()); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "positioned glyph at %u", + c->buffer->idx); + } + buffer->idx++; return_trace (true); } + bool + position_single (hb_font_t *font, + hb_direction_t direction, + hb_codepoint_t gid, + hb_glyph_position_t &pos) const + { + unsigned int index = (this+coverage).get_coverage (gid); + if (likely (index == NOT_COVERED)) return false; + if (unlikely (index >= valueCount)) return false; + + /* This is ugly... */ + hb_buffer_t buffer; + buffer.props.direction = direction; + OT::hb_ot_apply_context_t c (1, font, &buffer); + + valueFormat.apply_value (&c, this, + &values[index * valueFormat.get_len ()], + pos); + return true; + } + + template @@ -85,7 +121,7 @@ struct SinglePosFormat2 const SrcLookup *src, Iterator it, ValueFormat newFormat, - const hb_map_t *layout_variation_idx_map) + const hb_hashmap_t> *layout_variation_idx_delta_map) { auto out = c->extend_min (this); if (unlikely (!out)) return; @@ -95,7 +131,7 @@ struct SinglePosFormat2 + it | hb_map (hb_second) | hb_apply ([&] (hb_array_t _) - { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_map); }) + { src->get_value_format ().copy_values (c, newFormat, src, &_, layout_variation_idx_delta_map); }) ; auto glyphs = @@ -127,7 +163,7 @@ struct SinglePosFormat2 ; bool ret = bool (it); - SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_map); + SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned); return_trace (ret); } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh index b29f287bcee..1aa451abcc8 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GPOS/ValueFormat.hh @@ -59,6 +59,24 @@ struct ValueFormat : HBUINT16 unsigned int get_len () const { return hb_popcount ((unsigned int) *this); } unsigned int get_size () const { return get_len () * Value::static_size; } + hb_vector_t get_device_table_indices () const { + unsigned i = 0; + hb_vector_t result; + unsigned format = *this; + + if (format & xPlacement) i++; + if (format & yPlacement) i++; + if (format & xAdvance) i++; + if (format & yAdvance) i++; + + if (format & xPlaDevice) result.push (i++); + if (format & yPlaDevice) result.push (i++); + if (format & xAdvDevice) result.push (i++); + if (format & yAdvDevice) result.push (i++); + + return result; + } + bool apply_value (hb_ot_apply_context_t *c, const void *base, const Value *values, @@ -145,30 +163,50 @@ struct ValueFormat : HBUINT16 unsigned int new_format, const void *base, const Value *values, - const hb_map_t *layout_variation_idx_map) const + const hb_hashmap_t> *layout_variation_idx_delta_map) const { unsigned int format = *this; if (!format) return; - if (format & xPlacement) copy_value (c, new_format, xPlacement, *values++); - if (format & yPlacement) copy_value (c, new_format, yPlacement, *values++); - if (format & xAdvance) copy_value (c, new_format, xAdvance, *values++); - if (format & yAdvance) copy_value (c, new_format, yAdvance, *values++); + HBINT16 *x_placement = nullptr, *y_placement = nullptr, *x_adv = nullptr, *y_adv = nullptr; + if (format & xPlacement) x_placement = copy_value (c, new_format, xPlacement, *values++); + if (format & yPlacement) y_placement = copy_value (c, new_format, yPlacement, *values++); + if (format & xAdvance) x_adv = copy_value (c, new_format, xAdvance, *values++); + if (format & yAdvance) y_adv = copy_value (c, new_format, yAdvance, *values++); - if (format & xPlaDevice) copy_device (c, base, values++, layout_variation_idx_map); - if (format & yPlaDevice) copy_device (c, base, values++, layout_variation_idx_map); - if (format & xAdvDevice) copy_device (c, base, values++, layout_variation_idx_map); - if (format & yAdvDevice) copy_device (c, base, values++, layout_variation_idx_map); + if (format & xPlaDevice) + { + add_delta_to_value (x_placement, base, values, layout_variation_idx_delta_map); + copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xPlaDevice); + } + + if (format & yPlaDevice) + { + add_delta_to_value (y_placement, base, values, layout_variation_idx_delta_map); + copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yPlaDevice); + } + + if (format & xAdvDevice) + { + add_delta_to_value (x_adv, base, values, layout_variation_idx_delta_map); + copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, xAdvDevice); + } + + if (format & yAdvDevice) + { + add_delta_to_value (y_adv, base, values, layout_variation_idx_delta_map); + copy_device (c, base, values++, layout_variation_idx_delta_map, new_format, yAdvDevice); + } } - void copy_value (hb_serialize_context_t *c, - unsigned int new_format, - Flags flag, - Value value) const + HBINT16* copy_value (hb_serialize_context_t *c, + unsigned int new_format, + Flags flag, + Value value) const { // Filter by new format. - if (!(new_format & flag)) return; - c->copy (value); + if (!(new_format & flag)) return nullptr; + return reinterpret_cast (c->copy (value)); } void collect_variation_indices (hb_collect_variation_indices_context_t *c, @@ -183,31 +221,40 @@ struct ValueFormat : HBUINT16 if (format & yAdvance) i++; if (format & xPlaDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } if (format & ValueFormat::yPlaDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } if (format & ValueFormat::xAdvDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } if (format & ValueFormat::yAdvDevice) { - (base + get_device (&(values[i]))).collect_variation_indices (c->layout_variation_indices); + (base + get_device (&(values[i]))).collect_variation_indices (c); i++; } } + unsigned drop_device_table_flags () const + { + unsigned format = *this; + for (unsigned flag = xPlaDevice; flag <= yAdvDevice; flag = flag << 1) + format = format & ~flag; + + return format; + } + private: bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const { @@ -236,9 +283,27 @@ struct ValueFormat : HBUINT16 return *static_cast *> (value); } + void add_delta_to_value (HBINT16 *value, + const void *base, + const Value *src_value, + const hb_hashmap_t> *layout_variation_idx_delta_map) const + { + if (!value) return; + unsigned varidx = (base + get_device (src_value)).get_variation_index (); + hb_pair_t *varidx_delta; + if (!layout_variation_idx_delta_map->has (varidx, &varidx_delta)) return; + + *value += hb_second (*varidx_delta); + } + bool copy_device (hb_serialize_context_t *c, const void *base, - const Value *src_value, const hb_map_t *layout_variation_idx_map) const + const Value *src_value, + const hb_hashmap_t> *layout_variation_idx_delta_map, + unsigned int new_format, Flags flag) const { + // Filter by new format. + if (!(new_format & flag)) return true; + Value *dst_value = c->copy (*src_value); if (!dst_value) return false; @@ -246,7 +311,7 @@ struct ValueFormat : HBUINT16 *dst_value = 0; c->push (); - if ((base + get_device (src_value)).copy (c, layout_variation_idx_map)) + if ((base + get_device (src_value)).copy (c, layout_variation_idx_delta_map)) { c->add_link (*dst_value, c->pop_pack ()); return true; @@ -306,7 +371,7 @@ struct ValueFormat : HBUINT16 for (unsigned int i = 0; i < count; i++) { if (!sanitize_value_devices (c, base, values)) return_trace (false); - values += stride; + values = &StructAtOffset (values, stride); } return_trace (true); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh index 484f3474686..b5d506f36f9 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSet.hh @@ -5,12 +5,13 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { +template struct AlternateSet { protected: - Array16Of + Array16Of alternates; /* Array of alternate GlyphIDs--in * arbitrary order */ public: @@ -56,8 +57,23 @@ struct AlternateSet if (unlikely (alt_index > count || alt_index == 0)) return_trace (false); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->sync_so_far (); + c->buffer->message (c->font, + "replacing glyph at %u (alternate substitution)", + c->buffer->idx); + } + c->replace_glyph (alternates[alt_index - 1]); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "replaced glyph at %u (alternate substitution)", + c->buffer->idx - 1u); + } + return_trace (true); } @@ -68,7 +84,7 @@ struct AlternateSet { if (alternates.len && alternate_count) { - + alternates.sub_array (start_offset, alternate_count) + + alternates.as_array ().sub_array (start_offset, alternate_count) | hb_sink (hb_array (alternate_glyphs, *alternate_count)) ; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh index e5d999261fc..8951f5a7a17 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubst.hh @@ -6,28 +6,36 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct AlternateSubst { protected: union { - HBUINT16 format; /* Format identifier */ - AlternateSubstFormat1 format1; + HBUINT16 format; /* Format identifier */ + AlternateSubstFormat1_2 format1; +#ifndef HB_NO_BEYOND_64K + AlternateSubstFormat1_2 format2; +#endif } u; public: template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } + /* TODO This function is unused and not updated to 24bit GIDs. Should be done by using + * iterators. While at it perhaps using iterator of arrays of hb_codepoint_t instead. */ bool serialize (hb_serialize_context_t *c, hb_sorted_array_t glyphs, hb_array_t alternate_len_list, @@ -42,6 +50,9 @@ struct AlternateSubst default:return_trace (false); } } + + /* TODO subset() should choose format. */ + }; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh index af1cd7bedba..adec65d5864 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/AlternateSubstFormat1.hh @@ -6,20 +6,21 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { -struct AlternateSubstFormat1 +template +struct AlternateSubstFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To + typename Types::template OffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - Array16OfOffset16To + Array16Of>> alternateSet; /* Array of AlternateSet tables * ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (6, alternateSet); + DEFINE_SIZE_ARRAY (2 + 2 * Types::size, alternateSet); bool sanitize (hb_sanitize_context_t *c) const { @@ -39,9 +40,8 @@ struct AlternateSubstFormat1 | hb_filter (c->parent_active_glyphs (), hb_first) | hb_map (hb_second) | hb_map (hb_add (this)) - | hb_apply ([c] (const AlternateSet &_) { _.closure (c); }) + | hb_apply ([c] (const AlternateSet &_) { _.closure (c); }) ; - } void closure_lookups (hb_closure_lookups_context_t *c) const {} @@ -52,7 +52,7 @@ struct AlternateSubstFormat1 + hb_zip (this+coverage, alternateSet) | hb_map (hb_second) | hb_map (hb_add (this)) - | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); }) + | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); }) ; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ChainContextSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ChainContextSubst.hh index bbb88b222f8..08fd779f730 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ChainContextSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ChainContextSubst.hh @@ -7,7 +7,7 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct ChainContextSubst : ChainContext {}; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Common.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Common.hh index f4c78a9f020..968bba0481a 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Common.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Common.hh @@ -6,7 +6,7 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { typedef hb_pair_t hb_codepoint_pair_t; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ContextSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ContextSubst.hh index 2af54e8ff47..9f8cb46b5e2 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ContextSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ContextSubst.hh @@ -7,7 +7,7 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct ContextSubst : Context {}; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ExtensionSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ExtensionSubst.hh index 40a3ff439f1..831a7dfa2d1 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ExtensionSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ExtensionSubst.hh @@ -7,7 +7,7 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct ExtensionSubst : Extension { diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/GSUB.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/GSUB.hh index 3f0c4b2ad9a..900cf603e45 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/GSUB.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/GSUB.hh @@ -1,16 +1,15 @@ #ifndef OT_LAYOUT_GSUB_GSUB_HH #define OT_LAYOUT_GSUB_GSUB_HH -// TODO(garretrieger): move to new layout. #include "../../../hb-ot-layout-gsubgpos.hh" #include "Common.hh" #include "SubstLookup.hh" -using OT::Layout::GSUB::SubstLookup; - namespace OT { + +using Layout::GSUB_impl::SubstLookup; + namespace Layout { -namespace GSUB { /* * GSUB -- Glyph Substitution @@ -28,12 +27,15 @@ struct GSUB : GSUBGPOS bool subset (hb_subset_context_t *c) const { - hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features); + hb_subset_layout_context_t l (c, tableTag); return GSUBGPOS::subset (&l); } bool sanitize (hb_sanitize_context_t *c) const - { return GSUBGPOS::sanitize (c); } + { + TRACE_SANITIZE (this); + return_trace (GSUBGPOS::sanitize (c)); + } HB_INTERNAL bool is_blocklisted (hb_blob_t *blob, hb_face_t *face) const; @@ -47,11 +49,10 @@ struct GSUB : GSUBGPOS }; -} } -struct GSUB_accelerator_t : Layout::GSUB::GSUB::accelerator_t { - GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::GSUB::accelerator_t (face) {} +struct GSUB_accelerator_t : Layout::GSUB::accelerator_t { + GSUB_accelerator_t (hb_face_t *face) : Layout::GSUB::accelerator_t (face) {} }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh index 0448d925d12..b0fdd91dc22 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Ligature.hh @@ -5,18 +5,20 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { +template struct Ligature { protected: - HBGlyphID16 ligGlyph; /* GlyphID of ligature to substitute */ - HeadlessArrayOf + typename Types::HBGlyphID + ligGlyph; /* GlyphID of ligature to substitute */ + HeadlessArrayOf component; /* Array of component GlyphIDs--start * with the second component--ordered * in writing direction */ public: - DEFINE_SIZE_ARRAY (4, component); + DEFINE_SIZE_ARRAY (Types::size + 2, component); bool sanitize (hb_sanitize_context_t *c) const { @@ -62,7 +64,24 @@ struct Ligature * as a "ligated" substitution. */ if (unlikely (count == 1)) { + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->sync_so_far (); + c->buffer->message (c->font, + "replacing glyph at %u (ligature substitution)", + c->buffer->idx); + } + c->replace_glyph (ligGlyph); + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "replaced glyph at %u (ligature substitution)", + c->buffer->idx - 1u); + } + return_trace (true); } @@ -83,6 +102,31 @@ struct Ligature return_trace (false); } + unsigned pos = 0; + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + unsigned delta = c->buffer->sync_so_far (); + + pos = c->buffer->idx; + + char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0}; + char *p = buf; + + match_end += delta; + for (unsigned i = 0; i < count; i++) + { + match_positions[i] += delta; + if (i) + *p++ = ','; + snprintf (p, sizeof(buf) - (p - buf), "%u", match_positions[i]); + p += strlen(p); + } + + c->buffer->message (c->font, + "ligating glyphs at %s", + buf); + } + ligate_input (c, count, match_positions, @@ -90,6 +134,14 @@ struct Ligature ligGlyph, total_component_count); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->sync_so_far (); + c->buffer->message (c->font, + "ligated glyph at %u", + pos); + } + return_trace (true); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh index 185b324b35b..637cec71377 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSet.hh @@ -6,12 +6,13 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { +template struct LigatureSet { protected: - Array16OfOffset16To + Array16OfOffset16To> ligature; /* Array LigatureSet tables * ordered by preference */ public: @@ -28,7 +29,7 @@ struct LigatureSet return + hb_iter (ligature) | hb_map (hb_add (this)) - | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); }) + | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); }) | hb_any ; } @@ -37,7 +38,7 @@ struct LigatureSet { + hb_iter (ligature) | hb_map (hb_add (this)) - | hb_apply ([c] (const Ligature &_) { _.closure (c); }) + | hb_apply ([c] (const Ligature &_) { _.closure (c); }) ; } @@ -45,7 +46,7 @@ struct LigatureSet { + hb_iter (ligature) | hb_map (hb_add (this)) - | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); }) + | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); }) ; } @@ -54,7 +55,7 @@ struct LigatureSet return + hb_iter (ligature) | hb_map (hb_add (this)) - | hb_map ([c] (const Ligature &_) { return _.would_apply (c); }) + | hb_map ([c] (const Ligature &_) { return _.would_apply (c); }) | hb_any ; } @@ -65,7 +66,7 @@ struct LigatureSet unsigned int num_ligs = ligature.len; for (unsigned int i = 0; i < num_ligs; i++) { - const Ligature &lig = this+ligature[i]; + const auto &lig = this+ligature[i]; if (lig.apply (c)) return_trace (true); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh index a029bf5e9f4..cffa910295f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubst.hh @@ -6,28 +6,37 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct LigatureSubst { protected: union { - HBUINT16 format; /* Format identifier */ - LigatureSubstFormat1 format1; + HBUINT16 format; /* Format identifier */ + LigatureSubstFormat1_2 format1; +#ifndef HB_NO_BEYOND_64K + LigatureSubstFormat1_2 format2; +#endif } u; public: template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } + /* TODO This function is only used by small GIDs, and not updated to 24bit GIDs. Should + * be done by using iterators. While at it perhaps using iterator of arrays of hb_codepoint_t + * instead. */ bool serialize (hb_serialize_context_t *c, hb_sorted_array_t first_glyphs, hb_array_t ligature_per_first_glyph_count_list, @@ -49,6 +58,9 @@ struct LigatureSubst default:return_trace (false); } } + + /* TODO subset() should choose format. */ + }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh index 19dfe984694..32b642c38ad 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/LigatureSubstFormat1.hh @@ -6,20 +6,21 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { -struct LigatureSubstFormat1 +template +struct LigatureSubstFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To + typename Types::template OffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - Array16OfOffset16To + Array16Of>> ligatureSet; /* Array LigatureSet tables * ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (6, ligatureSet); + DEFINE_SIZE_ARRAY (4 + Types::size, ligatureSet); bool sanitize (hb_sanitize_context_t *c) const { @@ -33,7 +34,7 @@ struct LigatureSubstFormat1 + hb_zip (this+coverage, ligatureSet) | hb_filter (*glyphs, hb_first) | hb_map (hb_second) - | hb_map ([this, glyphs] (const Offset16To &_) + | hb_map ([this, glyphs] (const typename Types::template OffsetTo> &_) { return (this+_).intersects (glyphs); }) | hb_any ; @@ -48,7 +49,7 @@ struct LigatureSubstFormat1 | hb_filter (c->parent_active_glyphs (), hb_first) | hb_map (hb_second) | hb_map (hb_add (this)) - | hb_apply ([c] (const LigatureSet &_) { _.closure (c); }) + | hb_apply ([c] (const LigatureSet &_) { _.closure (c); }) ; } @@ -62,7 +63,7 @@ struct LigatureSubstFormat1 + hb_zip (this+coverage, ligatureSet) | hb_map (hb_second) | hb_map (hb_add (this)) - | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); }) + | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); }) ; } @@ -73,7 +74,7 @@ struct LigatureSubstFormat1 unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); if (likely (index == NOT_COVERED)) return false; - const LigatureSet &lig_set = this+ligatureSet[index]; + const auto &lig_set = this+ligatureSet[index]; return lig_set.would_apply (c); } @@ -84,7 +85,7 @@ struct LigatureSubstFormat1 unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); - const LigatureSet &lig_set = this+ligatureSet[index]; + const auto &lig_set = this+ligatureSet[index]; return_trace (lig_set.apply (c)); } @@ -128,7 +129,7 @@ struct LigatureSubstFormat1 hb_set_t new_coverage; + hb_zip (this+coverage, hb_iter (ligatureSet) | hb_map (hb_add (this))) | hb_filter (glyphset, hb_first) - | hb_filter ([&] (const LigatureSet& _) { + | hb_filter ([&] (const LigatureSet& _) { return _.intersects (&glyphset); }, hb_second) | hb_map (hb_first) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh index b2891755048..cf3d754e3cc 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubst.hh @@ -6,14 +6,17 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct MultipleSubst { protected: union { - HBUINT16 format; /* Format identifier */ - MultipleSubstFormat1 format1; + HBUINT16 format; /* Format identifier */ + MultipleSubstFormat1_2 format1; +#ifndef HB_NO_BEYOND_64K + MultipleSubstFormat1_2 format2; +#endif } u; public: @@ -21,28 +24,34 @@ struct MultipleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } + template bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t glyphs, - hb_array_t substitute_len_list, - hb_array_t substitute_glyphs_list) + Iterator it) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (u.format))) return_trace (false); unsigned int format = 1; u.format = format; switch (u.format) { - case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list)); + case 1: return_trace (u.format1.serialize (c, it)); default:return_trace (false); } } + + /* TODO subset() should choose format. */ + }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubstFormat1.hh index 54c6dc84783..4a9972c29cc 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/MultipleSubstFormat1.hh @@ -6,20 +6,21 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { -struct MultipleSubstFormat1 +template +struct MultipleSubstFormat1_2 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To + typename Types::template OffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - Array16OfOffset16To + Array16Of>> sequence; /* Array of Sequence tables * ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (6, sequence); + DEFINE_SIZE_ARRAY (4 + Types::size, sequence); bool sanitize (hb_sanitize_context_t *c) const { @@ -39,7 +40,7 @@ struct MultipleSubstFormat1 | hb_filter (c->parent_active_glyphs (), hb_first) | hb_map (hb_second) | hb_map (hb_add (this)) - | hb_apply ([c] (const Sequence &_) { _.closure (c); }) + | hb_apply ([c] (const Sequence &_) { _.closure (c); }) ; } @@ -51,7 +52,7 @@ struct MultipleSubstFormat1 + hb_zip (this+coverage, sequence) | hb_map (hb_second) | hb_map (hb_add (this)) - | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); }) + | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); }) ; } @@ -70,22 +71,31 @@ struct MultipleSubstFormat1 return_trace ((this+sequence[index]).apply (c)); } + template bool serialize (hb_serialize_context_t *c, - hb_sorted_array_t glyphs, - hb_array_t substitute_len_list, - hb_array_t substitute_glyphs_list) + Iterator it) { TRACE_SERIALIZE (this); + auto sequences = + + it + | hb_map (hb_second) + ; + auto glyphs = + + it + | hb_map_retains_sorting (hb_first) + ; if (unlikely (!c->extend_min (this))) return_trace (false); - if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false); - for (unsigned int i = 0; i < glyphs.length; i++) + + if (unlikely (!sequence.serialize (c, sequences.length))) return_trace (false); + + for (auto& pair : hb_zip (sequences, sequence)) { - unsigned int substitute_len = substitute_len_list[i]; - if (unlikely (!sequence[i] - .serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len)))) + if (unlikely (!pair.second + .serialize_serialize (c, pair.first))) return_trace (false); - substitute_glyphs_list += substitute_len; } + return_trace (coverage.serialize_serialize (c, glyphs)); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh index 435d80fd310..5ad463fea79 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubst.hh @@ -6,7 +6,7 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct ReverseChainSingleSubst { @@ -20,8 +20,8 @@ struct ReverseChainSingleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); default:return_trace (c->default_return_value ()); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh index 7a79a9df25e..73f222746e5 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh @@ -5,7 +5,7 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct ReverseChainSingleSubstFormat1 { @@ -33,10 +33,10 @@ struct ReverseChainSingleSubstFormat1 TRACE_SANITIZE (this); if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) return_trace (false); - const Array16OfOffset16To &lookahead = StructAfter> (backtrack); + const auto &lookahead = StructAfter (backtrack); if (!lookahead.sanitize (c, this)) return_trace (false); - const Array16Of &substitute = StructAfter> (lookahead); + const auto &substitute = StructAfter (lookahead); return_trace (substitute.sanitize (c)); } @@ -45,7 +45,7 @@ struct ReverseChainSingleSubstFormat1 if (!(this+coverage).intersects (glyphs)) return false; - const Array16OfOffset16To &lookahead = StructAfter> (backtrack); + const auto &lookahead = StructAfter (backtrack); unsigned int count; @@ -69,8 +69,8 @@ struct ReverseChainSingleSubstFormat1 { if (!intersects (c->glyphs)) return; - const Array16OfOffset16To &lookahead = StructAfter> (backtrack); - const Array16Of &substitute = StructAfter> (lookahead); + const auto &lookahead = StructAfter (backtrack); + const auto &substitute = StructAfter (lookahead); + hb_zip (this+coverage, substitute) | hb_filter (c->parent_active_glyphs (), hb_first) @@ -91,12 +91,12 @@ struct ReverseChainSingleSubstFormat1 for (unsigned int i = 0; i < count; i++) if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return; - const Array16OfOffset16To &lookahead = StructAfter> (backtrack); + const auto &lookahead = StructAfter (backtrack); count = lookahead.len; for (unsigned int i = 0; i < count; i++) if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return; - const Array16Of &substitute = StructAfter> (lookahead); + const auto &substitute = StructAfter (lookahead); count = substitute.len; c->output->add_array (substitute.arrayZ, substitute.len); } @@ -115,8 +115,8 @@ struct ReverseChainSingleSubstFormat1 unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint); if (likely (index == NOT_COVERED)) return_trace (false); - const Array16OfOffset16To &lookahead = StructAfter> (backtrack); - const Array16Of &substitute = StructAfter> (lookahead); + const auto &lookahead = StructAfter (backtrack); + const auto &substitute = StructAfter (lookahead); if (unlikely (index >= substitute.len)) return_trace (false); @@ -131,7 +131,23 @@ struct ReverseChainSingleSubstFormat1 c->buffer->idx + 1, &end_index)) { c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index); + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "replacing glyph at %u (reverse chaining substitution)", + c->buffer->idx); + } + c->replace_glyph_inplace (substitute[index]); + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "replaced glyph at %u (reverse chaining substitution)", + c->buffer->idx); + } + /* Note: We DON'T decrease buffer->idx. The main loop does it * for us. This is useful for preventing surprises if someone * calls us through a Context lookup. */ @@ -206,8 +222,8 @@ struct ReverseChainSingleSubstFormat1 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); const hb_map_t &glyph_map = *c->plan->glyph_map; - const Array16OfOffset16To &lookahead = StructAfter> (backtrack); - const Array16Of &substitute = StructAfter> (lookahead); + const auto &lookahead = StructAfter (backtrack); + const auto &substitute = StructAfter (lookahead); auto it = + hb_zip (this+coverage, substitute) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh index ebd451e6ba3..62d68160c7b 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/Sequence.hh @@ -5,12 +5,13 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { +template struct Sequence { protected: - Array16Of + Array16Of substitute; /* String of GlyphIDs to substitute */ public: DEFINE_SIZE_ARRAY (2, substitute); @@ -39,17 +40,58 @@ struct Sequence * as a "multiplied" substitution. */ if (unlikely (count == 1)) { + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->sync_so_far (); + c->buffer->message (c->font, + "replacing glyph at %u (multiple substitution)", + c->buffer->idx); + } + c->replace_glyph (substitute.arrayZ[0]); + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "replaced glyph at %u (multiple subtitution)", + c->buffer->idx - 1u); + } + return_trace (true); } /* Spec disallows this, but Uniscribe allows it. * https://github.com/harfbuzz/harfbuzz/issues/253 */ else if (unlikely (count == 0)) { + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->sync_so_far (); + c->buffer->message (c->font, + "deleting glyph at %u (multiple substitution)", + c->buffer->idx); + } + c->buffer->delete_glyph (); + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->sync_so_far (); + c->buffer->message (c->font, + "deleted glyph at %u (multiple substitution)", + c->buffer->idx); + } + return_trace (true); } + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->sync_so_far (); + c->buffer->message (c->font, + "multiplying glyph at %u", + c->buffer->idx); + } + unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur()); @@ -64,6 +106,26 @@ struct Sequence } c->buffer->skip_glyph (); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->sync_so_far (); + + char buf[HB_MAX_CONTEXT_LENGTH * 16] = {0}; + char *p = buf; + + for (unsigned i = c->buffer->idx - count; i < c->buffer->idx; i++) + { + if (buf < p) + *p++ = ','; + snprintf (p, sizeof(buf) - (p - buf), "%u", i); + p += strlen(p); + } + + c->buffer->message (c->font, + "multiplied glyphs at %s", + buf); + } + return_trace (true); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh index 786428fe453..304d1928e23 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubst.hh @@ -7,15 +7,19 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct SingleSubst { protected: union { - HBUINT16 format; /* Format identifier */ - SingleSubstFormat1 format1; - SingleSubstFormat2 format2; + HBUINT16 format; /* Format identifier */ + SingleSubstFormat1_3 format1; + SingleSubstFormat2_4 format2; +#ifndef HB_NO_BEYOND_64K + SingleSubstFormat1_3 format3; + SingleSubstFormat2_4 format4; +#endif } u; public: @@ -23,11 +27,15 @@ struct SingleSubst template typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { + if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value (); TRACE_DISPATCH (this, u.format); - if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ()); switch (u.format) { case 1: return_trace (c->dispatch (u.format1, std::forward (ds)...)); case 2: return_trace (c->dispatch (u.format2, std::forward (ds)...)); +#ifndef HB_NO_BEYOND_64K + case 3: return_trace (c->dispatch (u.format3, std::forward (ds)...)); + case 4: return_trace (c->dispatch (u.format4, std::forward (ds)...)); +#endif default:return_trace (c->default_return_value ()); } } @@ -45,11 +53,24 @@ struct SingleSubst if (glyphs) { format = 1; + hb_codepoint_t mask = 0xFFFFu; + +#ifndef HB_NO_BEYOND_64K + if (+ glyphs + | hb_map_retains_sorting (hb_first) + | hb_filter ([] (hb_codepoint_t gid) { return gid > 0xFFFFu; })) + { + format += 2; + mask = 0xFFFFFFu; + } +#endif + auto get_delta = [=] (hb_codepoint_pair_t _) - { return (unsigned) (_.second - _.first) & 0xFFFF; }; + { return (unsigned) (_.second - _.first) & mask; }; delta = get_delta (*glyphs); - if (!hb_all (++(+glyphs), delta, get_delta)) format = 2; + if (!hb_all (++(+glyphs), delta, get_delta)) format += 1; } + u.format = format; switch (u.format) { case 1: return_trace (u.format1.serialize (c, @@ -57,6 +78,13 @@ struct SingleSubst | hb_map_retains_sorting (hb_first), delta)); case 2: return_trace (u.format2.serialize (c, glyphs)); +#ifndef HB_NO_BEYOND_64K + case 3: return_trace (u.format3.serialize (c, + + glyphs + | hb_map_retains_sorting (hb_first), + delta)); + case 4: return_trace (u.format4.serialize (c, glyphs)); +#endif default:return_trace (false); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh index 3c6b2954cec..1fe9488e212 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat1.hh @@ -5,20 +5,22 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { -struct SingleSubstFormat1 +template +struct SingleSubstFormat1_3 { protected: HBUINT16 format; /* Format identifier--format = 1 */ - Offset16To + typename Types::template OffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - HBUINT16 deltaGlyphID; /* Add to original GlyphID to get + typename Types::HBUINT + deltaGlyphID; /* Add to original GlyphID to get * substitute GlyphID, modulo 0x10000 */ public: - DEFINE_SIZE_STATIC (6); + DEFINE_SIZE_STATIC (2 + 2 * Types::size); bool sanitize (hb_sanitize_context_t *c) const { @@ -26,6 +28,9 @@ struct SingleSubstFormat1 return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); } + hb_codepoint_t get_mask () const + { return (1 << (8 * Types::size)) - 1; } + bool intersects (const hb_set_t *glyphs) const { return (this+coverage).intersects (glyphs); } @@ -34,14 +39,33 @@ struct SingleSubstFormat1 void closure (hb_closure_context_t *c) const { - unsigned d = deltaGlyphID; - - + hb_iter (this+coverage) - | hb_filter (c->parent_active_glyphs ()) - | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; }) + hb_codepoint_t d = deltaGlyphID; + hb_codepoint_t mask = get_mask (); + + /* Help fuzzer avoid this function as much. */ + unsigned pop = (this+coverage).get_population (); + if (pop >= mask) + return; + + hb_set_t intersection; + (this+coverage).intersect_set (c->parent_active_glyphs (), intersection); + + /* In degenerate fuzzer-found fonts, but not real fonts, + * this table can keep adding new glyphs in each round of closure. + * Refuse to close-over, if it maps glyph range to overlapping range. */ + hb_codepoint_t min_before = intersection.get_min (); + hb_codepoint_t max_before = intersection.get_max (); + hb_codepoint_t min_after = (min_before + d) & mask; + hb_codepoint_t max_after = (max_before + d) & mask; + if (intersection.get_population () == max_before - min_before + 1 && + ((min_before <= min_after && min_after <= max_before) || + (min_before <= max_after && max_after <= max_before))) + return; + + + hb_iter (intersection) + | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; }) | hb_sink (c->output) ; - } void closure_lookups (hb_closure_lookups_context_t *c) const {} @@ -49,9 +73,11 @@ struct SingleSubstFormat1 void collect_glyphs (hb_collect_glyphs_context_t *c) const { if (unlikely (!(this+coverage).collect_coverage (c->input))) return; - unsigned d = deltaGlyphID; + hb_codepoint_t d = deltaGlyphID; + hb_codepoint_t mask = get_mask (); + + hb_iter (this+coverage) - | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; }) + | hb_map ([d, mask] (hb_codepoint_t g) { return (g + d) & mask; }) | hb_sink (c->output) ; } @@ -68,11 +94,28 @@ struct SingleSubstFormat1 unsigned int index = (this+coverage).get_coverage (glyph_id); if (likely (index == NOT_COVERED)) return_trace (false); - /* According to the Adobe Annotated OpenType Suite, result is always - * limited to 16bit. */ - glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu; + hb_codepoint_t d = deltaGlyphID; + hb_codepoint_t mask = get_mask (); + + glyph_id = (glyph_id + d) & mask; + + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->sync_so_far (); + c->buffer->message (c->font, + "replacing glyph at %u (single substitution)", + c->buffer->idx); + } + c->replace_glyph (glyph_id); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "replaced glyph at %u (single substitution)", + c->buffer->idx - 1u); + } + return_trace (true); } @@ -95,14 +138,17 @@ struct SingleSubstFormat1 const hb_set_t &glyphset = *c->plan->glyphset_gsub (); const hb_map_t &glyph_map = *c->plan->glyph_map; - hb_codepoint_t delta = deltaGlyphID; + hb_codepoint_t d = deltaGlyphID; + hb_codepoint_t mask = get_mask (); + + hb_set_t intersection; + (this+coverage).intersect_set (glyphset, intersection); auto it = - + hb_iter (this+coverage) - | hb_filter (glyphset) - | hb_map_retains_sorting ([&] (hb_codepoint_t g) { + + hb_iter (intersection) + | hb_map_retains_sorting ([d, mask] (hb_codepoint_t g) { return hb_codepoint_pair_t (g, - (g + delta) & 0xFFFF); }) + (g + d) & mask); }) | hb_filter (glyphset, hb_second) | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh index df75bb52bbc..908cc2af158 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SingleSubstFormat2.hh @@ -5,21 +5,22 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { -struct SingleSubstFormat2 +template +struct SingleSubstFormat2_4 { protected: HBUINT16 format; /* Format identifier--format = 2 */ - Offset16To + typename Types::template OffsetTo coverage; /* Offset to Coverage table--from * beginning of Substitution table */ - Array16Of + Array16Of substitute; /* Array of substitute * GlyphIDs--ordered by Coverage Index */ public: - DEFINE_SIZE_ARRAY (6, substitute); + DEFINE_SIZE_ARRAY (4 + Types::size, substitute); bool sanitize (hb_sanitize_context_t *c) const { @@ -35,12 +36,27 @@ struct SingleSubstFormat2 void closure (hb_closure_context_t *c) const { - + hb_zip (this+coverage, substitute) - | hb_filter (c->parent_active_glyphs (), hb_first) + auto &cov = this+coverage; + auto &glyph_set = c->parent_active_glyphs (); + + if (substitute.len > glyph_set.get_population () * 4) + { + for (auto g : glyph_set) + { + unsigned i = cov.get_coverage (g); + if (i == NOT_COVERED || i >= substitute.len) + continue; + c->output->add (substitute.arrayZ[i]); + } + + return; + } + + + hb_zip (cov, substitute) + | hb_filter (glyph_set, hb_first) | hb_map (hb_second) | hb_sink (c->output) ; - } void closure_lookups (hb_closure_lookups_context_t *c) const {} @@ -67,8 +83,23 @@ struct SingleSubstFormat2 if (unlikely (index >= substitute.len)) return_trace (false); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->sync_so_far (); + c->buffer->message (c->font, + "replacing glyph at %u (single substitution)", + c->buffer->idx); + } + c->replace_glyph (substitute[index]); + if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ()) + { + c->buffer->message (c->font, + "replaced glyph at %u (single substitution)", + c->buffer->idx - 1u); + } + return_trace (true); } @@ -103,7 +134,7 @@ struct SingleSubstFormat2 + hb_zip (this+coverage, substitute) | hb_filter (glyphset, hb_first) | hb_filter (glyphset, hb_second) - | hb_map_retains_sorting ([&] (hb_pair_t p) -> hb_codepoint_pair_t + | hb_map_retains_sorting ([&] (hb_pair_t p) -> hb_codepoint_pair_t { return hb_pair (glyph_map[p.first], glyph_map[p.second]); }) ; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookup.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookup.hh index 8fb3b550976..5796cc3be57 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookup.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookup.hh @@ -6,7 +6,7 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct SubstLookup : Lookup { @@ -25,7 +25,7 @@ struct SubstLookup : Lookup { unsigned int type = get_type (); if (unlikely (type == SubTable::Extension)) - return reinterpret_cast (get_subtable (0)).is_reverse (); + return get_subtable (0).u.extension.is_reverse (); return lookup_type_is_reverse (type); } @@ -98,10 +98,15 @@ struct SubstLookup : Lookup return dispatch (c); } + template bool serialize_single (hb_serialize_context_t *c, uint32_t lookup_props, - hb_sorted_array_t glyphs, - hb_array_t substitutes) + Glyphs glyphs, + Substitutes substitutes) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false); @@ -114,19 +119,16 @@ struct SubstLookup : Lookup return_trace (false); } - bool serialize_multiple (hb_serialize_context_t *c, - uint32_t lookup_props, - hb_sorted_array_t glyphs, - hb_array_t substitute_len_list, - hb_array_t substitute_glyphs_list) + template + bool serialize (hb_serialize_context_t *c, + uint32_t lookup_props, + Iterator it) { TRACE_SERIALIZE (this); if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false); if (c->push ()->u.multiple. - serialize (c, - glyphs, - substitute_len_list, - substitute_glyphs_list)) + serialize (c, it)) { c->add_link (get_subtables ()[0], c->pop_pack ()); return_trace (true); diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookupSubTable.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookupSubTable.hh index 53e963e2a29..a525fba0399 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookupSubTable.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/GSUB/SubstLookupSubTable.hh @@ -13,7 +13,7 @@ namespace OT { namespace Layout { -namespace GSUB { +namespace GSUB_impl { struct SubstLookupSubTable { diff --git a/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh b/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh new file mode 100644 index 00000000000..6a43403e94b --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/Layout/types.hh @@ -0,0 +1,66 @@ +/* + * Copyright © 2007,2008,2009 Red Hat, Inc. + * Copyright © 2010,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod, Garret Rieger + */ + +#ifndef OT_LAYOUT_TYPES_HH +#define OT_LAYOUT_TYPES_HH + +namespace OT { +namespace Layout { + +struct SmallTypes { + static constexpr unsigned size = 2; + using large_int = uint32_t; + using HBUINT = HBUINT16; + using HBGlyphID = HBGlyphID16; + using Offset = Offset16; + template + using OffsetTo = OT::Offset16To; + template + using ArrayOf = OT::Array16Of; + template + using SortedArrayOf = OT::SortedArray16Of; +}; + +struct MediumTypes { + static constexpr unsigned size = 3; + using large_int = uint64_t; + using HBUINT = HBUINT24; + using HBGlyphID = HBGlyphID24; + using Offset = Offset24; + template + using OffsetTo = OT::Offset24To; + template + using ArrayOf = OT::Array24Of; + template + using SortedArrayOf = OT::SortedArray24Of; +}; + +} +} + +#endif /* OT_LAYOUT_TYPES_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh index 7ebf64d0d5c..e24f3408ca6 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/CompositeGlyph.hh @@ -3,6 +3,7 @@ #include "../../hb-open-type.hh" +#include "composite-iter.hh" namespace OT { @@ -25,13 +26,20 @@ struct CompositeGlyphRecord USE_MY_METRICS = 0x0200, OVERLAP_COMPOUND = 0x0400, SCALED_COMPONENT_OFFSET = 0x0800, - UNSCALED_COMPONENT_OFFSET = 0x1000 + UNSCALED_COMPONENT_OFFSET = 0x1000, +#ifndef HB_NO_BEYOND_64K + GID_IS_24BIT = 0x2000 +#endif }; public: unsigned int get_size () const { unsigned int size = min_size; + /* glyphIndex is 24bit instead of 16bit */ +#ifndef HB_NO_BEYOND_64K + if (flags & GID_IS_24BIT) size += HBGlyphID24::static_size - HBGlyphID16::static_size; +#endif /* arg1 and 2 are int16 */ if (flags & ARG_1_AND_2_ARE_WORDS) size += 4; /* arg1 and 2 are int8 */ @@ -60,7 +68,13 @@ struct CompositeGlyphRecord bool is_anchored () const { return !(flags & ARGS_ARE_XY_VALUES); } void get_anchor_points (unsigned int &point1, unsigned int &point2) const { - const HBUINT8 *p = &StructAfter (glyphIndex); + const auto *p = &StructAfter (flags); +#ifndef HB_NO_BEYOND_64K + if (flags & GID_IS_24BIT) + p += HBGlyphID24::static_size; + else +#endif + p += HBGlyphID16::static_size; if (flags & ARG_1_AND_2_ARE_WORDS) { point1 = ((const HBUINT16 *) p)[0]; @@ -92,6 +106,67 @@ struct CompositeGlyphRecord } } + unsigned compile_with_deltas (const contour_point_t &p_delta, + char *out) const + { + const HBINT8 *p = &StructAfter (flags); +#ifndef HB_NO_BEYOND_64K + if (flags & GID_IS_24BIT) + p += HBGlyphID24::static_size; + else +#endif + p += HBGlyphID16::static_size; + + unsigned len = get_size (); + unsigned len_before_val = (const char *)p - (const char *)this; + if (flags & ARG_1_AND_2_ARE_WORDS) + { + // no overflow, copy and update value with deltas + hb_memcpy (out, this, len); + + const HBINT16 *px = reinterpret_cast (p); + HBINT16 *o = reinterpret_cast (out + len_before_val); + o[0] = px[0] + roundf (p_delta.x); + o[1] = px[1] + roundf (p_delta.y); + } + else + { + int new_x = p[0] + roundf (p_delta.x); + int new_y = p[1] + roundf (p_delta.y); + if (new_x <= 127 && new_x >= -128 && + new_y <= 127 && new_y >= -128) + { + hb_memcpy (out, this, len); + HBINT8 *o = reinterpret_cast (out + len_before_val); + o[0] = new_x; + o[1] = new_y; + } + else + { + // int8 overflows after deltas applied + hb_memcpy (out, this, len_before_val); + + //update flags + CompositeGlyphRecord *o = reinterpret_cast (out); + o->flags = flags | ARG_1_AND_2_ARE_WORDS; + out += len_before_val; + + HBINT16 new_value; + new_value = new_x; + hb_memcpy (out, &new_value, HBINT16::static_size); + out += HBINT16::static_size; + + new_value = new_y; + hb_memcpy (out, &new_value, HBINT16::static_size); + out += HBINT16::static_size; + + hb_memcpy (out, p+2, len - len_before_val - 2); + len += 2; + } + } + return len; + } + protected: bool scaled_offsets () const { return (flags & (SCALED_COMPONENT_OFFSET | UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; } @@ -101,8 +176,14 @@ struct CompositeGlyphRecord matrix[0] = matrix[3] = 1.f; matrix[1] = matrix[2] = 0.f; + const auto *p = &StructAfter (flags); +#ifndef HB_NO_BEYOND_64K + if (flags & GID_IS_24BIT) + p += HBGlyphID24::static_size; + else +#endif + p += HBGlyphID16::static_size; int tx, ty; - const HBINT8 *p = &StructAfter (glyphIndex); if (flags & ARG_1_AND_2_ARE_WORDS) { tx = *(const HBINT16 *) p; @@ -145,62 +226,35 @@ struct CompositeGlyphRecord } public: - HBUINT16 flags; - HBGlyphID16 glyphIndex; - public: - DEFINE_SIZE_MIN (4); -}; - -struct composite_iter_t : hb_iter_with_fallback_t -{ - typedef const CompositeGlyphRecord *__item_t__; - composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) : - glyph (glyph_), current (nullptr), current_size (0) + hb_codepoint_t get_gid () const { - set_current (current_); +#ifndef HB_NO_BEYOND_64K + if (flags & GID_IS_24BIT) + return StructAfter (flags); + else +#endif + return StructAfter (flags); } - - composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {} - - item_t __item__ () const { return *current; } - bool __more__ () const { return current; } - void __next__ () + void set_gid (hb_codepoint_t gid) { - if (!current->has_more ()) { current = nullptr; return; } - - set_current (&StructAtOffset (current, current_size)); - } - composite_iter_t __end__ () const { return composite_iter_t (); } - bool operator != (const composite_iter_t& o) const - { return current != o.current; } - - - void set_current (__item_t__ current_) - { - if (!glyph.check_range (current_, CompositeGlyphRecord::min_size)) - { - current = nullptr; - current_size = 0; - return; - } - unsigned size = current_->get_size (); - if (!glyph.check_range (current_, size)) - { - current = nullptr; - current_size = 0; - return; - } - - current = current_; - current_size = size; +#ifndef HB_NO_BEYOND_64K + if (flags & GID_IS_24BIT) + StructAfter (flags) = gid; + else +#endif + /* TODO assert? */ + StructAfter (flags) = gid; } - private: - hb_bytes_t glyph; - __item_t__ current; - unsigned current_size; + protected: + HBUINT16 flags; + HBUINT24 pad; + public: + DEFINE_SIZE_MIN (4); }; +using composite_iter_t = composite_iter_tmpl; + struct CompositeGlyph { const GlyphHeader &header; @@ -248,6 +302,63 @@ struct CompositeGlyph return; glyph_chain.set_overlaps_flag (); } + + bool compile_bytes_with_deltas (const hb_bytes_t &source_bytes, + const contour_point_vector_t &deltas, + hb_bytes_t &dest_bytes /* OUT */) + { + if (source_bytes.length <= GlyphHeader::static_size || + header.numberOfContours != -1) + { + dest_bytes = hb_bytes_t (); + return true; + } + + unsigned source_len = source_bytes.length - GlyphHeader::static_size; + + /* try to allocate more memories than source glyph bytes + * in case that there might be an overflow for int8 value + * and we would need to use int16 instead */ + char *o = (char *) hb_calloc (source_len + source_len/2, sizeof (char)); + if (unlikely (!o)) return false; + + const CompositeGlyphRecord *c = reinterpret_cast (source_bytes.arrayZ + GlyphHeader::static_size); + auto it = composite_iter_t (hb_bytes_t ((const char *)c, source_len), c); + + char *p = o; + unsigned i = 0, source_comp_len = 0; + for (const auto &component : it) + { + /* last 4 points in deltas are phantom points and should not be included */ + if (i >= deltas.length - 4) return false; + + unsigned comp_len = component.get_size (); + if (component.is_anchored ()) + { + hb_memcpy (p, &component, comp_len); + p += comp_len; + } + else + { + unsigned new_len = component.compile_with_deltas (deltas[i], p); + p += new_len; + } + i++; + source_comp_len += comp_len; + } + + //copy instructions if any + if (source_len > source_comp_len) + { + unsigned instr_len = source_len - source_comp_len; + hb_memcpy (p, (const char *)c + source_comp_len, instr_len); + p += instr_len; + } + + unsigned len = p - o; + dest_bytes = hb_bytes_t (o, len); + return true; + } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh index 3d2095ac2df..7cd1f571bbc 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/Glyph.hh @@ -7,6 +7,8 @@ #include "GlyphHeader.hh" #include "SimpleGlyph.hh" #include "CompositeGlyph.hh" +#include "VarCompositeGlyph.hh" +#include "coord-setter.hh" namespace OT { @@ -27,7 +29,7 @@ enum phantom_point_index_t struct Glyph { - enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE }; + enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE, VAR_COMPOSITE }; public: composite_iter_t get_composite_iterator () const @@ -35,6 +37,11 @@ struct Glyph if (type != COMPOSITE) return composite_iter_t (); return CompositeGlyph (*header, bytes).iter (); } + var_composite_iter_t get_var_composite_iterator () const + { + if (type != VAR_COMPOSITE) return var_composite_iter_t (); + return VarCompositeGlyph (*header, bytes).iter (); + } const hb_bytes_t trim_padding () const { @@ -72,22 +79,212 @@ struct Glyph } } + void update_mtx (const hb_subset_plan_t *plan, + int xMin, int xMax, + int yMin, int yMax, + const contour_point_vector_t &all_points) const + { + hb_codepoint_t new_gid = 0; + if (!plan->new_gid_for_old_gid (gid, &new_gid)) + return; + + if (type != EMPTY) + { + plan->bounds_width_map.set (new_gid, xMax - xMin); + plan->bounds_height_map.set (new_gid, yMax - yMin); + } + + unsigned len = all_points.length; + float leftSideX = all_points[len - 4].x; + float rightSideX = all_points[len - 3].x; + float topSideY = all_points[len - 2].y; + float bottomSideY = all_points[len - 1].y; + + signed hori_aw = roundf (rightSideX - leftSideX); + if (hori_aw < 0) hori_aw = 0; + int lsb = roundf (xMin - leftSideX); + plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb)); + //flag value should be computed using non-empty glyphs + if (type != EMPTY && lsb != xMin) + plan->head_maxp_info.allXMinIsLsb = false; + + signed vert_aw = roundf (topSideY - bottomSideY); + if (vert_aw < 0) vert_aw = 0; + int tsb = roundf (topSideY - yMax); + plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb)); + } + + bool compile_header_bytes (const hb_subset_plan_t *plan, + const contour_point_vector_t &all_points, + hb_bytes_t &dest_bytes /* OUT */) const + { + GlyphHeader *glyph_header = nullptr; + if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4) + { + glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size); + if (unlikely (!glyph_header)) return false; + } + + float xMin = 0, xMax = 0; + float yMin = 0, yMax = 0; + if (all_points.length > 4) + { + xMin = xMax = all_points[0].x; + yMin = yMax = all_points[0].y; + } + + for (unsigned i = 1; i < all_points.length - 4; i++) + { + float x = all_points[i].x; + float y = all_points[i].y; + xMin = hb_min (xMin, x); + xMax = hb_max (xMax, x); + yMin = hb_min (yMin, y); + yMax = hb_max (yMax, y); + } + + update_mtx (plan, roundf (xMin), roundf (xMax), roundf (yMin), roundf (yMax), all_points); + + int rounded_xMin = roundf (xMin); + int rounded_xMax = roundf (xMax); + int rounded_yMin = roundf (yMin); + int rounded_yMax = roundf (yMax); + + if (type != EMPTY) + { + plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin); + plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin); + plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax); + plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax); + } + + /* when pinned at default, no need to compile glyph header + * and for empty glyphs: all_points only include phantom points. + * just update metrics and then return */ + if (!glyph_header) + return true; + + glyph_header->numberOfContours = header->numberOfContours; + + glyph_header->xMin = rounded_xMin; + glyph_header->yMin = rounded_yMin; + glyph_header->xMax = rounded_xMax; + glyph_header->yMax = rounded_yMax; + + dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size); + return true; + } + + bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, + hb_font_t *font, + const glyf_accelerator_t &glyf, + hb_bytes_t &dest_start, /* IN/OUT */ + hb_bytes_t &dest_end /* OUT */) + { + contour_point_vector_t all_points, deltas; + unsigned composite_contours = 0; + head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info; + unsigned *composite_contours_p = &composite_contours; + + // don't compute head/maxp values when glyph has no contours(type is EMPTY) + // also ignore .notdef glyph when --notdef-outline is not enabled + if (type == EMPTY || + (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))) + { + head_maxp_info_p = nullptr; + composite_contours_p = nullptr; + } + + if (!get_points (font, glyf, all_points, &deltas, head_maxp_info_p, composite_contours_p, false, false)) + return false; + + // .notdef, set type to empty so we only update metrics and don't compile bytes for + // it + if (gid == 0 && + !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) + { + type = EMPTY; + dest_start = hb_bytes_t (); + dest_end = hb_bytes_t (); + } + + //dont compile bytes when pinned at default, just recalculate bounds + if (!plan->pinned_at_default) { + switch (type) { + case COMPOSITE: + if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start, + deltas, + dest_end)) + return false; + break; + case SIMPLE: + if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points, + plan->flags & HB_SUBSET_FLAGS_NO_HINTING, + dest_end)) + return false; + break; + default: + /* set empty bytes for empty glyph + * do not use source glyph's pointers */ + dest_start = hb_bytes_t (); + dest_end = hb_bytes_t (); + break; + } + } + + if (!compile_header_bytes (plan, all_points, dest_start)) + { + dest_end.fini (); + return false; + } + return true; + } + + /* Note: Recursively calls itself. * all_points includes phantom points */ template bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator, contour_point_vector_t &all_points /* OUT */, + contour_point_vector_t *deltas = nullptr, /* OUT */ + head_maxp_info_t * head_maxp_info = nullptr, /* OUT */ + unsigned *composite_contours = nullptr, /* OUT */ + bool shift_points_hori = true, + bool use_my_metrics = true, bool phantom_only = false, - unsigned int depth = 0) const + hb_array_t coords = hb_array_t (), + unsigned int depth = 0, + unsigned *edge_count = nullptr) const { if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false; + unsigned stack_edge_count = 0; + if (!edge_count) edge_count = &stack_edge_count; + if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false; + (*edge_count)++; + + if (head_maxp_info) + { + head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth); + } + + if (!coords) + coords = hb_array (font->coords, font->num_coords); + contour_point_vector_t stack_points; bool inplace = type == SIMPLE && all_points.length == 0; /* Load into all_points if it's empty, as an optimization. */ contour_point_vector_t &points = inplace ? all_points : stack_points; switch (type) { + case SIMPLE: + if (depth == 0 && head_maxp_info) + head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours); + if (depth > 0 && composite_contours) + *composite_contours += (unsigned) header->numberOfContours; + if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) + return false; + break; case COMPOSITE: { /* pseudo component points for each component in composite glyph */ @@ -95,29 +292,36 @@ struct Glyph if (unlikely (!points.resize (num_points))) return false; break; } - case SIMPLE: - if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only))) - return false; +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: + { + for (auto &item : get_var_composite_iterator ()) + if (unlikely (!item.get_points (points))) return false; + } +#endif + default: break; } /* Init phantom points */ if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false; - hb_array_t phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); + hb_array_t phantoms = points.as_array ().sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); { - int h_delta = (int) header->xMin - - glyf_accelerator.hmtx->get_side_bearing (gid); + int lsb = 0; + int h_delta = glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb) ? + (int) header->xMin - lsb : 0; + HB_UNUSED int tsb = 0; int v_orig = (int) header->yMax + #ifndef HB_NO_VERTICAL - glyf_accelerator.vmtx->get_side_bearing (gid) + ((void) glyf_accelerator.vmtx->get_leading_bearing_without_var_unscaled (gid, &tsb), tsb) #else 0 #endif ; - unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid); + unsigned h_adv = glyf_accelerator.hmtx->get_advance_without_var_unscaled (gid); unsigned v_adv = #ifndef HB_NO_VERTICAL - glyf_accelerator.vmtx->get_advance (gid) + glyf_accelerator.vmtx->get_advance_without_var_unscaled (gid) #else - font->face->get_upem () #endif @@ -128,12 +332,33 @@ struct Glyph phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv; } + if (deltas != nullptr && depth == 0 && type == COMPOSITE) + { + if (unlikely (!deltas->resize (points.length))) return false; + deltas->copy_vector (points); + } + #ifndef HB_NO_VAR - glyf_accelerator.gvar->apply_deltas_to_points (gid, font, points.as_array ()); + glyf_accelerator.gvar->apply_deltas_to_points (gid, + coords, + points.as_array ()); #endif + // mainly used by CompositeGlyph calculating new X/Y offset value so no need to extend it + // with child glyphs' points + if (deltas != nullptr && depth == 0 && type == COMPOSITE) + { + for (unsigned i = 0 ; i < points.length; i++) + { + deltas->arrayZ[i].x = points.arrayZ[i].x - deltas->arrayZ[i].x; + deltas->arrayZ[i].y = points.arrayZ[i].y - deltas->arrayZ[i].y; + } + } + switch (type) { case SIMPLE: + if (depth == 0 && head_maxp_info) + head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, points.length - 4); if (!inplace) all_points.extend (points.as_array ()); break; @@ -144,13 +369,23 @@ struct Glyph for (auto &item : get_composite_iterator ()) { comp_points.reset (); - if (unlikely (!glyf_accelerator.glyph_for_gid (item.glyphIndex) - .get_points (font, glyf_accelerator, comp_points, - phantom_only, depth + 1))) + if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) + .get_points (font, + glyf_accelerator, + comp_points, + deltas, + head_maxp_info, + composite_contours, + shift_points_hori, + use_my_metrics, + phantom_only, + coords, + depth + 1, + edge_count))) return false; /* Copy phantom points from component if USE_MY_METRICS flag set */ - if (item.is_use_my_metrics ()) + if (use_my_metrics && item.is_use_my_metrics ()) for (unsigned int i = 0; i < PHANTOM_COUNT; i++) phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; @@ -174,18 +409,80 @@ struct Glyph } } - all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT)); + all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT)); + + if (all_points.length > HB_GLYF_MAX_POINTS) + return false; comp_index++; } + if (head_maxp_info && depth == 0) + { + if (composite_contours) + head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours); + head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length); + head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index); + } + all_points.extend (phantoms); + } break; +#ifndef HB_NO_VAR_COMPOSITES + case VAR_COMPOSITE: + { + contour_point_vector_t comp_points; + hb_array_t points_left = points.as_array (); + for (auto &item : get_var_composite_iterator ()) + { + hb_array_t record_points = points_left.sub_array (0, item.get_num_points ()); + + comp_points.reset (); + + auto component_coords = coords; + if (item.is_reset_unspecified_axes ()) + component_coords = hb_array (); + + coord_setter_t coord_setter (component_coords); + item.set_variations (coord_setter, record_points); + + if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ()) + .get_points (font, + glyf_accelerator, + comp_points, + deltas, + head_maxp_info, + nullptr, + shift_points_hori, + use_my_metrics, + phantom_only, + coord_setter.get_coords (), + depth + 1, + edge_count))) + return false; + + /* Apply component transformation */ + item.transform_points (record_points, comp_points); + + /* Copy phantom points from component if USE_MY_METRICS flag set */ + if (use_my_metrics && item.is_use_my_metrics ()) + for (unsigned int i = 0; i < PHANTOM_COUNT; i++) + phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i]; + + all_points.extend (comp_points.as_array ().sub_array (0, comp_points.length - PHANTOM_COUNT)); + + if (all_points.length > HB_GLYF_MAX_POINTS) + return false; + + points_left += item.get_num_points (); + } all_points.extend (phantoms); } break; +#endif default: all_points.extend (phantoms); + break; } - if (depth == 0) /* Apply at top level */ + if (depth == 0 && shift_points_hori) /* Apply at top level */ { /* Undocumented rasterizer behavior: * Shift points horizontally by the updated left side bearing @@ -198,23 +495,30 @@ struct Glyph return !all_points.in_error (); } - bool get_extents (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator, - hb_glyph_extents_t *extents) const + bool get_extents_without_var_scaled (hb_font_t *font, const glyf_accelerator_t &glyf_accelerator, + hb_glyph_extents_t *extents) const { if (type == EMPTY) return true; /* Empty glyph; zero extents. */ - return header->get_extents (font, glyf_accelerator, gid, extents); + return header->get_extents_without_var_scaled (font, glyf_accelerator, gid, extents); } hb_bytes_t get_bytes () const { return bytes; } - Glyph (hb_bytes_t bytes_ = hb_bytes_t (), - hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), - header (bytes.as ()), - gid (gid_) + Glyph () : bytes (), + header (bytes.as ()), + gid (-1), + type(EMPTY) + {} + + Glyph (hb_bytes_t bytes_, + hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_), + header (bytes.as ()), + gid (gid_) { int num_contours = header->numberOfContours; if (unlikely (num_contours == 0)) type = EMPTY; else if (num_contours > 0) type = SIMPLE; + else if (num_contours == -2) type = VAR_COMPOSITE; else type = COMPOSITE; /* negative numbers */ } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/GlyphHeader.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/GlyphHeader.hh index a2a83fe198a..72c99f88cdd 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/GlyphHeader.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/GlyphHeader.hh @@ -14,15 +14,19 @@ struct GlyphHeader bool has_data () const { return numberOfContours; } template - bool get_extents (hb_font_t *font, const accelerator_t &glyf_accelerator, - hb_codepoint_t gid, hb_glyph_extents_t *extents) const + bool get_extents_without_var_scaled (hb_font_t *font, const accelerator_t &glyf_accelerator, + hb_codepoint_t gid, hb_glyph_extents_t *extents) const { /* Undocumented rasterizer behavior: shift glyph to the left by (lsb - xMin), i.e., xMin = lsb */ /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */ - extents->x_bearing = font->em_scale_x (glyf_accelerator.hmtx->get_side_bearing (gid)); - extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax)); - extents->width = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax)); - extents->height = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax)); + int lsb = hb_min (xMin, xMax); + (void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb); + extents->x_bearing = lsb; + extents->y_bearing = hb_max (yMin, yMax); + extents->width = hb_max (xMin, xMax) - hb_min (xMin, xMax); + extents->height = hb_min (yMin, yMax) - hb_max (yMin, yMax); + + font->scale_glyph_extents (extents); return true; } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh index 4b74967928b..432f368079f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SimpleGlyph.hh @@ -20,7 +20,7 @@ struct SimpleGlyph FLAG_X_SAME = 0x10, FLAG_Y_SAME = 0x20, FLAG_OVERLAP_SIMPLE = 0x40, - FLAG_RESERVED2 = 0x80 + FLAG_CUBIC = 0x80 }; const GlyphHeader &header; @@ -132,8 +132,8 @@ struct SimpleGlyph if (unlikely (p + 1 > end)) return false; unsigned int repeat_count = *p++; unsigned stop = hb_min (i + repeat_count, count); - for (; i < stop;) - points_.arrayZ[i++].flag = flag; + for (; i < stop; i++) + points_.arrayZ[i].flag = flag; } } return true; @@ -184,7 +184,7 @@ struct SimpleGlyph if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false; unsigned int num_points = endPtsOfContours[num_contours - 1] + 1; - points_.alloc (num_points + 4); // Allocate for phantom points, to avoid a possible copy + points_.alloc (num_points + 4, true); // Allocate for phantom points, to avoid a possible copy if (!points_.resize (num_points)) return false; if (phantom_only) return true; @@ -206,6 +206,129 @@ struct SimpleGlyph && read_points (p, points_, end, &contour_point_t::y, FLAG_Y_SHORT, FLAG_Y_SAME); } + + static void encode_coord (int value, + uint8_t &flag, + const simple_glyph_flag_t short_flag, + const simple_glyph_flag_t same_flag, + hb_vector_t &coords /* OUT */) + { + if (value == 0) + { + flag |= same_flag; + } + else if (value >= -255 && value <= 255) + { + flag |= short_flag; + if (value > 0) flag |= same_flag; + else value = -value; + + coords.arrayZ[coords.length++] = (uint8_t) value; + } + else + { + int16_t val = value; + coords.arrayZ[coords.length++] = val >> 8; + coords.arrayZ[coords.length++] = val & 0xff; + } + } + + static void encode_flag (uint8_t &flag, + uint8_t &repeat, + uint8_t lastflag, + hb_vector_t &flags /* OUT */) + { + if (flag == lastflag && repeat != 255) + { + repeat++; + if (repeat == 1) + { + /* We know there's room. */ + flags.arrayZ[flags.length++] = flag; + } + else + { + unsigned len = flags.length; + flags.arrayZ[len-2] = flag | FLAG_REPEAT; + flags.arrayZ[len-1] = repeat; + } + } + else + { + repeat = 0; + flags.push (flag); + } + } + + bool compile_bytes_with_deltas (const contour_point_vector_t &all_points, + bool no_hinting, + hb_bytes_t &dest_bytes /* OUT */) + { + if (header.numberOfContours == 0 || all_points.length <= 4) + { + dest_bytes = hb_bytes_t (); + return true; + } + unsigned num_points = all_points.length - 4; + + hb_vector_t flags, x_coords, y_coords; + if (unlikely (!flags.alloc (num_points, true))) return false; + if (unlikely (!x_coords.alloc (2*num_points, true))) return false; + if (unlikely (!y_coords.alloc (2*num_points, true))) return false; + + uint8_t lastflag = 255, repeat = 0; + int prev_x = 0, prev_y = 0; + + for (unsigned i = 0; i < num_points; i++) + { + uint8_t flag = all_points.arrayZ[i].flag; + flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE; + + int cur_x = roundf (all_points.arrayZ[i].x); + int cur_y = roundf (all_points.arrayZ[i].y); + encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords); + encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords); + encode_flag (flag, repeat, lastflag, flags); + + prev_x = cur_x; + prev_y = cur_y; + lastflag = flag; + } + + unsigned len_before_instrs = 2 * header.numberOfContours + 2; + unsigned len_instrs = instructions_length (); + unsigned total_len = len_before_instrs + flags.length + x_coords.length + y_coords.length; + + if (!no_hinting) + total_len += len_instrs; + + char *p = (char *) hb_malloc (total_len); + if (unlikely (!p)) return false; + + const char *src = bytes.arrayZ + GlyphHeader::static_size; + char *cur = p; + hb_memcpy (p, src, len_before_instrs); + + cur += len_before_instrs; + src += len_before_instrs; + + if (!no_hinting) + { + hb_memcpy (cur, src, len_instrs); + cur += len_instrs; + } + + hb_memcpy (cur, flags.arrayZ, flags.length); + cur += flags.length; + + hb_memcpy (cur, x_coords.arrayZ, x_coords.length); + cur += x_coords.length; + + hb_memcpy (cur, y_coords.arrayZ, y_coords.length); + + dest_bytes = hb_bytes_t (p, total_len); + return true; + } }; diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh index 8106a80338e..9d1c8e22776 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/SubsetGlyph.hh @@ -6,12 +6,14 @@ namespace OT { + +struct glyf_accelerator_t; + namespace glyf_impl { struct SubsetGlyph { - hb_codepoint_t new_gid; hb_codepoint_t old_gid; Glyph source_glyph; hb_bytes_t dest_start; /* region of source_glyph to copy first */ @@ -19,14 +21,14 @@ struct SubsetGlyph bool serialize (hb_serialize_context_t *c, bool use_short_loca, - const hb_subset_plan_t *plan) const + const hb_subset_plan_t *plan) { TRACE_SERIALIZE (this); hb_bytes_t dest_glyph = dest_start.copy (c); dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); unsigned int pad_length = use_short_loca ? padding () : 0; - DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); + DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length); HBUINT8 pad; pad = 0; @@ -42,8 +44,8 @@ struct SubsetGlyph for (auto &_ : Glyph (dest_glyph).get_composite_iterator ()) { hb_codepoint_t new_gid; - if (plan->new_gid_for_old_gid (_.glyphIndex, &new_gid)) - const_cast (_).glyphIndex = new_gid; + if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid)) + const_cast (_).set_gid (new_gid); } if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) @@ -55,6 +57,17 @@ struct SubsetGlyph return_trace (true); } + bool compile_bytes_with_deltas (const hb_subset_plan_t *plan, + hb_font_t *font, + const glyf_accelerator_t &glyf) + { return source_glyph.compile_bytes_with_deltas (plan, font, glyf, dest_start, dest_end); } + + void free_compiled_bytes () + { + dest_start.fini (); + dest_end.fini (); + } + void drop_hints_bytes () { source_glyph.drop_hints_bytes (dest_start, dest_end); } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/VarCompositeGlyph.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/VarCompositeGlyph.hh new file mode 100644 index 00000000000..2b2d25f05cd --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/VarCompositeGlyph.hh @@ -0,0 +1,354 @@ +#ifndef OT_GLYF_VARCOMPOSITEGLYPH_HH +#define OT_GLYF_VARCOMPOSITEGLYPH_HH + + +#include "../../hb-open-type.hh" +#include "coord-setter.hh" + + +namespace OT { +namespace glyf_impl { + + +struct VarCompositeGlyphRecord +{ + protected: + enum var_composite_glyph_flag_t + { + USE_MY_METRICS = 0x0001, + AXIS_INDICES_ARE_SHORT = 0x0002, + UNIFORM_SCALE = 0x0004, + HAVE_TRANSLATE_X = 0x0008, + HAVE_TRANSLATE_Y = 0x0010, + HAVE_ROTATION = 0x0020, + HAVE_SCALE_X = 0x0040, + HAVE_SCALE_Y = 0x0080, + HAVE_SKEW_X = 0x0100, + HAVE_SKEW_Y = 0x0200, + HAVE_TCENTER_X = 0x0400, + HAVE_TCENTER_Y = 0x0800, + GID_IS_24 = 0x1000, + AXES_HAVE_VARIATION = 0x2000, + RESET_UNSPECIFIED_AXES = 0x4000, + }; + + public: + + unsigned int get_size () const + { + unsigned int size = min_size; + + unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 4 : 3; + size += numAxes * axis_width; + + // gid + size += 2; + if (flags & GID_IS_24) size += 1; + + if (flags & HAVE_TRANSLATE_X) size += 2; + if (flags & HAVE_TRANSLATE_Y) size += 2; + if (flags & HAVE_ROTATION) size += 2; + if (flags & HAVE_SCALE_X) size += 2; + if (flags & HAVE_SCALE_Y) size += 2; + if (flags & HAVE_SKEW_X) size += 2; + if (flags & HAVE_SKEW_Y) size += 2; + if (flags & HAVE_TCENTER_X) size += 2; + if (flags & HAVE_TCENTER_Y) size += 2; + + return size; + } + + bool has_more () const { return true; } + + bool is_use_my_metrics () const { return flags & USE_MY_METRICS; } + bool is_reset_unspecified_axes () const { return flags & RESET_UNSPECIFIED_AXES; } + + hb_codepoint_t get_gid () const + { + if (flags & GID_IS_24) + return StructAfter (numAxes); + else + return StructAfter (numAxes); + } + + unsigned get_numAxes () const + { + return numAxes; + } + + unsigned get_num_points () const + { + unsigned num = 0; + if (flags & AXES_HAVE_VARIATION) num += numAxes; + if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++; + if (flags & HAVE_ROTATION) num++; + if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++; + if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++; + if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++; + return num; + } + + void transform_points (hb_array_t record_points, + contour_point_vector_t &points) const + { + float matrix[4]; + contour_point_t trans; + + get_transformation_from_points (record_points, matrix, trans); + + points.transform (matrix); + points.translate (trans); + } + + static inline void transform (float (&matrix)[4], contour_point_t &trans, + float (other)[6]) + { + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L268 + float xx1 = other[0]; + float xy1 = other[1]; + float yx1 = other[2]; + float yy1 = other[3]; + float dx1 = other[4]; + float dy1 = other[5]; + float xx2 = matrix[0]; + float xy2 = matrix[1]; + float yx2 = matrix[2]; + float yy2 = matrix[3]; + float dx2 = trans.x; + float dy2 = trans.y; + + matrix[0] = xx1*xx2 + xy1*yx2; + matrix[1] = xx1*xy2 + xy1*yy2; + matrix[2] = yx1*xx2 + yy1*yx2; + matrix[3] = yx1*xy2 + yy1*yy2; + trans.x = xx2*dx1 + yx2*dy1 + dx2; + trans.y = xy2*dx1 + yy2*dy1 + dy2; + } + + static void translate (float (&matrix)[4], contour_point_t &trans, + float translateX, float translateY) + { + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L213 + float other[6] = {1.f, 0.f, 0.f, 1.f, translateX, translateY}; + transform (matrix, trans, other); + } + + static void scale (float (&matrix)[4], contour_point_t &trans, + float scaleX, float scaleY) + { + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L224 + float other[6] = {scaleX, 0.f, 0.f, scaleY, 0.f, 0.f}; + transform (matrix, trans, other); + } + + static void rotate (float (&matrix)[4], contour_point_t &trans, + float rotation) + { + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240 + rotation = rotation * float (M_PI); + float c = cosf (rotation); + float s = sinf (rotation); + float other[6] = {c, s, -s, c, 0.f, 0.f}; + transform (matrix, trans, other); + } + + static void skew (float (&matrix)[4], contour_point_t &trans, + float skewX, float skewY) + { + // https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255 + skewX = skewX * float (M_PI); + skewY = skewY * float (M_PI); + float other[6] = {1.f, tanf (skewY), tanf (skewX), 1.f, 0.f, 0.f}; + transform (matrix, trans, other); + } + + bool get_points (contour_point_vector_t &points) const + { + float translateX = 0.f; + float translateY = 0.f; + float rotation = 0.f; + float scaleX = 1.f * (1 << 10); + float scaleY = 1.f * (1 << 10); + float skewX = 0.f; + float skewY = 0.f; + float tCenterX = 0.f; + float tCenterY = 0.f; + + if (unlikely (!points.resize (points.length + get_num_points ()))) return false; + + unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1; + unsigned axes_size = numAxes * axis_width; + + const F2DOT14 *q = (const F2DOT14 *) (axes_size + + (flags & GID_IS_24 ? 3 : 2) + + &StructAfter (numAxes)); + + hb_array_t rec_points = points.as_array ().sub_array (points.length - get_num_points ()); + + unsigned count = numAxes; + if (flags & AXES_HAVE_VARIATION) + { + for (unsigned i = 0; i < count; i++) + rec_points[i].x = q++->to_int (); + rec_points += count; + } + else + q += count; + + const HBUINT16 *p = (const HBUINT16 *) q; + + if (flags & HAVE_TRANSLATE_X) translateX = * (const FWORD *) p++; + if (flags & HAVE_TRANSLATE_Y) translateY = * (const FWORD *) p++; + if (flags & HAVE_ROTATION) rotation = ((const F4DOT12 *) p++)->to_int (); + if (flags & HAVE_SCALE_X) scaleX = ((const F6DOT10 *) p++)->to_int (); + if (flags & HAVE_SCALE_Y) scaleY = ((const F6DOT10 *) p++)->to_int (); + if (flags & HAVE_SKEW_X) skewX = ((const F4DOT12 *) p++)->to_int (); + if (flags & HAVE_SKEW_Y) skewY = ((const F4DOT12 *) p++)->to_int (); + if (flags & HAVE_TCENTER_X) tCenterX = * (const FWORD *) p++; + if (flags & HAVE_TCENTER_Y) tCenterY = * (const FWORD *) p++; + + if ((flags & UNIFORM_SCALE) && !(flags & HAVE_SCALE_Y)) + scaleY = scaleX; + + if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) + { + rec_points[0].x = translateX; + rec_points[0].y = translateY; + rec_points++; + } + if (flags & HAVE_ROTATION) + { + rec_points[0].x = rotation; + rec_points++; + } + if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) + { + rec_points[0].x = scaleX; + rec_points[0].y = scaleY; + rec_points++; + } + if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) + { + rec_points[0].x = skewX; + rec_points[0].y = skewY; + rec_points++; + } + if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) + { + rec_points[0].x = tCenterX; + rec_points[0].y = tCenterY; + rec_points++; + } + assert (!rec_points); + + return true; + } + + void get_transformation_from_points (hb_array_t rec_points, + float (&matrix)[4], contour_point_t &trans) const + { + if (flags & AXES_HAVE_VARIATION) + rec_points += numAxes; + + matrix[0] = matrix[3] = 1.f; + matrix[1] = matrix[2] = 0.f; + trans.init (0.f, 0.f); + + float translateX = 0.f; + float translateY = 0.f; + float rotation = 0.f; + float scaleX = 1.f; + float scaleY = 1.f; + float skewX = 0.f; + float skewY = 0.f; + float tCenterX = 0.f; + float tCenterY = 0.f; + + if (flags & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) + { + translateX = rec_points[0].x; + translateY = rec_points[0].y; + rec_points++; + } + if (flags & HAVE_ROTATION) + { + rotation = rec_points[0].x / (1 << 12); + rec_points++; + } + if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y)) + { + scaleX = rec_points[0].x / (1 << 10); + scaleY = rec_points[0].y / (1 << 10); + rec_points++; + } + if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y)) + { + skewX = rec_points[0].x / (1 << 12); + skewY = rec_points[0].y / (1 << 12); + rec_points++; + } + if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) + { + tCenterX = rec_points[0].x; + tCenterY = rec_points[0].y; + rec_points++; + } + assert (!rec_points); + + translate (matrix, trans, translateX + tCenterX, translateY + tCenterY); + rotate (matrix, trans, rotation); + scale (matrix, trans, scaleX, scaleY); + skew (matrix, trans, -skewX, skewY); + translate (matrix, trans, -tCenterX, -tCenterY); + } + + void set_variations (coord_setter_t &setter, + hb_array_t rec_points) const + { + bool have_variations = flags & AXES_HAVE_VARIATION; + unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1; + + const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2)); + const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24 ? 3 : 2)); + + const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + numAxes) : (HBUINT8 *) (q + numAxes))); + + unsigned count = numAxes; + for (unsigned i = 0; i < count; i++) + { + unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++; + + signed v = have_variations ? rec_points[i].x : a++->to_int (); + + v = hb_clamp (v, -(1<<14), (1<<14)); + setter[axis_index] = v; + } + } + + protected: + HBUINT16 flags; + HBUINT8 numAxes; + public: + DEFINE_SIZE_MIN (3); +}; + +using var_composite_iter_t = composite_iter_tmpl; + +struct VarCompositeGlyph +{ + const GlyphHeader &header; + hb_bytes_t bytes; + VarCompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) : + header (header_), bytes (bytes_) {} + + var_composite_iter_t iter () const + { return var_composite_iter_t (bytes, &StructAfter (header)); } + +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + + +#endif /* OT_GLYF_VARCOMPOSITEGLYPH_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/composite-iter.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/composite-iter.hh new file mode 100644 index 00000000000..21e6b4ee962 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/composite-iter.hh @@ -0,0 +1,68 @@ +#ifndef OT_GLYF_COMPOSITE_ITER_HH +#define OT_GLYF_COMPOSITE_ITER_HH + + +#include "../../hb.hh" + + +namespace OT { +namespace glyf_impl { + + +template +struct composite_iter_tmpl : hb_iter_with_fallback_t, + const CompositeGlyphRecord &> +{ + typedef const CompositeGlyphRecord *__item_t__; + composite_iter_tmpl (hb_bytes_t glyph_, __item_t__ current_) : + glyph (glyph_), current (nullptr), current_size (0) + { + set_current (current_); + } + + composite_iter_tmpl () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {} + + const CompositeGlyphRecord & __item__ () const { return *current; } + bool __more__ () const { return current; } + void __next__ () + { + if (!current->has_more ()) { current = nullptr; return; } + + set_current (&StructAtOffset (current, current_size)); + } + composite_iter_tmpl __end__ () const { return composite_iter_tmpl (); } + bool operator != (const composite_iter_tmpl& o) const + { return current != o.current; } + + + void set_current (__item_t__ current_) + { + if (!glyph.check_range (current_, CompositeGlyphRecord::min_size)) + { + current = nullptr; + current_size = 0; + return; + } + unsigned size = current_->get_size (); + if (!glyph.check_range (current_, size)) + { + current = nullptr; + current_size = 0; + return; + } + + current = current_; + current_size = size; + } + + private: + hb_bytes_t glyph; + __item_t__ current; + unsigned current_size; +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + +#endif /* OT_GLYF_COMPOSITE_ITER_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/coord-setter.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/coord-setter.hh new file mode 100644 index 00000000000..df64ed5af7d --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/coord-setter.hh @@ -0,0 +1,34 @@ +#ifndef OT_GLYF_COORD_SETTER_HH +#define OT_GLYF_COORD_SETTER_HH + + +#include "../../hb.hh" + + +namespace OT { +namespace glyf_impl { + + +struct coord_setter_t +{ + coord_setter_t (hb_array_t coords) : + coords (coords) {} + + int& operator [] (unsigned idx) + { + if (coords.length < idx + 1) + coords.resize (idx + 1); + return coords[idx]; + } + + hb_array_t get_coords () + { return coords.as_array (); } + + hb_vector_t coords; +}; + + +} /* namespace glyf_impl */ +} /* namespace OT */ + +#endif /* OT_GLYF_COORD_SETTER_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf-helpers.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf-helpers.hh index 1fad84ce831..18e2d92d0f4 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf-helpers.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf-helpers.hh @@ -16,7 +16,7 @@ template static void -_write_loca (IteratorIn it, bool short_offsets, IteratorOut dest) +_write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest) { unsigned right_shift = short_offsets ? 1 : 0; unsigned int offset = 0; @@ -25,7 +25,7 @@ _write_loca (IteratorIn it, bool short_offsets, IteratorOut dest) | hb_map ([=, &offset] (unsigned int padded_size) { offset += padded_size; - DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset); + DEBUG_MSG (SUBSET, nullptr, "loca entry offset %u", offset); return offset >> right_shift; }) | hb_sink (dest) @@ -44,6 +44,20 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca) head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr); head_prime->indexToLocFormat = use_short_loca ? 0 : 1; + if (plan->normalized_coords) + { + head_prime->xMin = plan->head_maxp_info.xMin; + head_prime->xMax = plan->head_maxp_info.xMax; + head_prime->yMin = plan->head_maxp_info.yMin; + head_prime->yMax = plan->head_maxp_info.yMax; + + unsigned orig_flag = head_prime->flags; + if (plan->head_maxp_info.allXMinIsLsb) + orig_flag |= 1 << 1; + else + orig_flag &= ~(1 << 1); + head_prime->flags = orig_flag; + } bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob); hb_blob_destroy (head_prime_blob); @@ -61,7 +75,7 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s if (unlikely (!loca_prime_data)) return false; - DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d", + DEBUG_MSG (SUBSET, nullptr, "loca entry_size %u num_offsets %u size %u", entry_size, num_offsets, entry_size * num_offsets); if (use_short_loca) diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh index caaf2d1f2eb..7a25f07d328 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/glyf.hh @@ -7,6 +7,7 @@ #include "../../hb-ot-hmtx-table.hh" #include "../../hb-ot-var-gvar-table.hh" #include "../../hb-draw.hh" +#include "../../hb-paint.hh" #include "glyf-helpers.hh" #include "Glyph.hh" @@ -24,7 +25,6 @@ namespace OT { */ #define HB_OT_TAG_glyf HB_TAG('g','l','y','f') - struct glyf { friend struct glyf_accelerator_t; @@ -46,8 +46,11 @@ struct glyf const hb_subset_plan_t *plan) { TRACE_SERIALIZE (this); + unsigned init_len = c->length (); - for (const auto &_ : it) _.serialize (c, use_short_loca, plan); + for (auto &_ : it) + if (unlikely (!_.serialize (c, use_short_loca, plan))) + return false; /* As a special case when all glyph in the font are empty, add a zero byte * to the table, so that OTS doesn’t reject it, and to make the table work @@ -72,36 +75,67 @@ struct glyf glyf *glyf_prime = c->serializer->start_embed (); if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false); + hb_font_t *font = nullptr; + if (c->plan->normalized_coords) + { + font = _create_font_for_instancing (c->plan); + if (unlikely (!font)) return false; + } + + hb_vector_t padded_offsets; + unsigned num_glyphs = c->plan->num_output_glyphs (); + if (unlikely (!padded_offsets.resize (num_glyphs))) + return false; + hb_vector_t glyphs; - _populate_subset_glyphs (c->plan, &glyphs); + if (!_populate_subset_glyphs (c->plan, font, glyphs)) + return false; - auto padded_offsets = - + hb_iter (glyphs) - | hb_map (&glyf_impl::SubsetGlyph::padded_size) - ; + if (font) + hb_font_destroy (font); - unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0); - bool use_short_loca = max_offset < 0x1FFFF; + unsigned max_offset = 0; + for (unsigned i = 0; i < num_glyphs; i++) + { + padded_offsets[i] = glyphs[i].padded_size (); + max_offset += padded_offsets[i]; + } + bool use_short_loca = false; + if (likely (!c->plan->force_long_loca)) + use_short_loca = max_offset < 0x1FFFF; - glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); if (!use_short_loca) { - padded_offsets = - + hb_iter (glyphs) - | hb_map (&glyf_impl::SubsetGlyph::length) - ; + for (unsigned i = 0; i < num_glyphs; i++) + padded_offsets[i] = glyphs[i].length (); } + bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan); + if (c->plan->normalized_coords && !c->plan->pinned_at_default) + _free_compiled_subset_glyphs (glyphs, glyphs.length - 1); + + if (!result) return false; if (unlikely (c->serializer->in_error ())) return_trace (false); + return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan, - padded_offsets, + padded_offsets.iter (), use_short_loca))); } - void + bool _populate_subset_glyphs (const hb_subset_plan_t *plan, - hb_vector_t *glyphs /* OUT */) const; + hb_font_t *font, + hb_vector_t &glyphs /* OUT */) const; + + hb_font_t * + _create_font_for_instancing (const hb_subset_plan_t *plan) const; + + void _free_compiled_subset_glyphs (hb_vector_t &glyphs, unsigned index) const + { + for (unsigned i = 0; i <= index && i < glyphs.length; i++) + glyphs[i].free_compiled_bytes (); + } protected: UnsizedArrayOf @@ -166,7 +200,7 @@ struct glyf_accelerator_t contour_point_vector_t all_points; bool phantom_only = !consumer.is_consuming_contour_points (); - if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, phantom_only))) + if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only))) return false; if (consumer.is_consuming_contour_points ()) @@ -194,6 +228,7 @@ struct glyf_accelerator_t hb_font_t *font; hb_glyph_extents_t *extents; contour_point_t *phantoms; + bool scaled; struct contour_bounds_t { @@ -209,7 +244,7 @@ struct glyf_accelerator_t bool empty () const { return (min_x >= max_x) || (min_y >= max_y); } - void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) + void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scaled) { if (unlikely (empty ())) { @@ -219,26 +254,32 @@ struct glyf_accelerator_t extents->y_bearing = 0; return; } - extents->x_bearing = font->em_scalef_x (min_x); - extents->width = font->em_scalef_x (max_x) - extents->x_bearing; - extents->y_bearing = font->em_scalef_y (max_y); - extents->height = font->em_scalef_y (min_y) - extents->y_bearing; + { + extents->x_bearing = roundf (min_x); + extents->width = roundf (max_x - extents->x_bearing); + extents->y_bearing = roundf (max_y); + extents->height = roundf (min_y - extents->y_bearing); + + if (scaled) + font->scale_glyph_extents (extents); + } } protected: float min_x, min_y, max_x, max_y; } bounds; - points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_) + points_aggregator_t (hb_font_t *font_, hb_glyph_extents_t *extents_, contour_point_t *phantoms_, bool scaled_) { font = font_; extents = extents_; phantoms = phantoms_; + scaled = scaled_; if (extents) bounds = contour_bounds_t (); } void consume_point (const contour_point_t &point) { bounds.add (point); } - void points_end () { bounds.get_extents (font, extents); } + void points_end () { bounds.get_extents (font, extents, scaled); } bool is_consuming_contour_points () { return extents; } contour_point_t *get_phantoms_sink () { return phantoms; } @@ -246,22 +287,22 @@ struct glyf_accelerator_t public: unsigned - get_advance_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const + get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const { if (unlikely (gid >= num_glyphs)) return 0; bool success = false; contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; - if (likely (font->num_coords == gvar->get_axis_count ())) - success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms)); + if (font->num_coords) + success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms, false)); if (unlikely (!success)) return #ifndef HB_NO_VERTICAL - is_vertical ? vmtx->get_advance (gid) : + is_vertical ? vmtx->get_advance_without_var_unscaled (gid) : #endif - hmtx->get_advance (gid); + hmtx->get_advance_without_var_unscaled (gid); float result = is_vertical ? phantoms[glyf_impl::PHANTOM_TOP].y - phantoms[glyf_impl::PHANTOM_BOTTOM].y @@ -269,23 +310,20 @@ struct glyf_accelerator_t return hb_clamp (roundf (result), 0.f, (float) UINT_MAX / 2); } - int get_side_bearing_var (hb_font_t *font, hb_codepoint_t gid, bool is_vertical) const + bool get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t gid, bool is_vertical, int *lsb) const { - if (unlikely (gid >= num_glyphs)) return 0; + if (unlikely (gid >= num_glyphs)) return false; hb_glyph_extents_t extents; contour_point_t phantoms[glyf_impl::PHANTOM_COUNT]; - if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms)))) - return -#ifndef HB_NO_VERTICAL - is_vertical ? vmtx->get_side_bearing (gid) : -#endif - hmtx->get_side_bearing (gid); + if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms, false)))) + return false; - return is_vertical - ? ceilf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing - : floorf (phantoms[glyf_impl::PHANTOM_LEFT].x); + *lsb = is_vertical + ? roundf (phantoms[glyf_impl::PHANTOM_TOP].y) - extents.y_bearing + : roundf (phantoms[glyf_impl::PHANTOM_LEFT].x); + return true; } #endif @@ -296,9 +334,18 @@ struct glyf_accelerator_t #ifndef HB_NO_VAR if (font->num_coords) - return get_points (font, gid, points_aggregator_t (font, extents, nullptr)); + return get_points (font, gid, points_aggregator_t (font, extents, nullptr, true)); #endif - return glyph_for_gid (gid).get_extents (font, *this, extents); + return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents); + } + + bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const + { + funcs->push_clip_glyph (data, gid, font); + funcs->color (data, true, foreground); + funcs->pop_clip (data); + + return true; } const glyf_impl::Glyph @@ -349,37 +396,76 @@ struct glyf_accelerator_t }; -inline void +inline bool glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan, - hb_vector_t *glyphs /* OUT */) const + hb_font_t *font, + hb_vector_t& glyphs /* OUT */) const { OT::glyf_accelerator_t glyf (plan->source); + unsigned num_glyphs = plan->num_output_glyphs (); + if (!glyphs.resize (num_glyphs)) return false; - + hb_range (plan->num_output_glyphs ()) - | hb_map ([&] (hb_codepoint_t new_gid) - { - glyf_impl::SubsetGlyph subset_glyph = {0}; - subset_glyph.new_gid = new_gid; - - /* should never fail: all old gids should be mapped */ - if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid)) - return subset_glyph; - - if (new_gid == 0 && - !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) - subset_glyph.source_glyph = glyf_impl::Glyph (); - else - subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true); - if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) - subset_glyph.drop_hints_bytes (); - else - subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); - return subset_glyph; - }) - | hb_sink (glyphs) - ; + unsigned idx = 0; + for (auto p : plan->glyph_map->iter ()) + { + unsigned new_gid = p.second; + glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid]; + subset_glyph.old_gid = p.first; + + if (unlikely (new_gid == 0 && + !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) && + !plan->normalized_coords) + subset_glyph.source_glyph = glyf_impl::Glyph (); + else + { + /* If plan has an accelerator, the preprocessing step already trimmed glyphs. + * Don't trim them again! */ + subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, !plan->accelerator); + } + + if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING) + subset_glyph.drop_hints_bytes (); + else + subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes (); + + if (font) + { + if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf))) + { + // when pinned at default, only bounds are updated, thus no need to free + if (!plan->pinned_at_default && idx > 0) + _free_compiled_subset_glyphs (glyphs, idx - 1); + return false; + } + idx++; + } + } + return true; } +inline hb_font_t * +glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const +{ + hb_font_t *font = hb_font_create (plan->source); + if (unlikely (font == hb_font_get_empty ())) return nullptr; + + hb_vector_t vars; + if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true))) + return nullptr; + + for (auto _ : plan->user_axes_location) + { + hb_variation_t var; + var.tag = _.first; + var.value = _.second; + vars.push (var); + } + +#ifndef HB_NO_VAR + hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ()); +#endif + return font; +} } /* namespace OT */ diff --git a/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh b/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh index 853c7ed1eaa..ed410e2b16f 100644 --- a/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh +++ b/src/java.desktop/share/native/libharfbuzz/OT/glyf/path-builder.hh @@ -26,22 +26,29 @@ struct path_builder_t optional_point_t lerp (optional_point_t p, float t) { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } - } first_oncurve, first_offcurve, last_offcurve; + } first_oncurve, first_offcurve, last_offcurve, last_offcurve2; path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) { font = font_; draw_session = &draw_session_; - first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); } /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287 See also: * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html - * https://stackoverflow.com/a/20772557 */ + * https://stackoverflow.com/a/20772557 + * + * Cubic support added (incomplete). */ void consume_point (const contour_point_t &point) { bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE; +#ifdef HB_NO_CUBIC_GLYF + bool is_cubic = false; +#else + bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC); +#endif optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y)); if (!first_oncurve) { @@ -69,16 +76,41 @@ struct path_builder_t { if (is_on_curve) { - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - p.x, p.y); + if (last_offcurve2) + { + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + p.x, p.y); + last_offcurve2 = optional_point_t (); + } + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + p.x, p.y); last_offcurve = optional_point_t (); } else { - optional_point_t mid = last_offcurve.lerp (p, .5f); - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - mid.x, mid.y); - last_offcurve = p; + if (is_cubic && !last_offcurve2) + { + last_offcurve2 = last_offcurve; + last_offcurve = p; + } + else + { + optional_point_t mid = last_offcurve.lerp (p, .5f); + + if (is_cubic) + { + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + last_offcurve2 = optional_point_t (); + } + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + mid.x, mid.y); + last_offcurve = p; + } } } else @@ -105,8 +137,15 @@ struct path_builder_t draw_session->quadratic_to (first_offcurve.x, first_offcurve.y, first_oncurve.x, first_oncurve.y); else if (last_offcurve && first_oncurve) - draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, - first_oncurve.x, first_oncurve.y); + { + if (last_offcurve2) + draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y, + last_offcurve.x, last_offcurve.y, + first_oncurve.x, first_oncurve.y); + else + draw_session->quadratic_to (last_offcurve.x, last_offcurve.y, + first_oncurve.x, first_oncurve.y); + } else if (first_oncurve) draw_session->line_to (first_oncurve.x, first_oncurve.y); else if (first_offcurve) @@ -117,7 +156,7 @@ struct path_builder_t } /* Getting ready for the next contour */ - first_oncurve = first_offcurve = last_offcurve = optional_point_t (); + first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t (); draw_session->close_path (); } } diff --git a/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh b/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh new file mode 100644 index 00000000000..15ff7a8bdb7 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/OT/name/name.hh @@ -0,0 +1,589 @@ +/* + * Copyright © 2011,2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef OT_NAME_NAME_HH +#define OT_NAME_NAME_HH + +#include "../../hb-open-type.hh" +#include "../../hb-ot-name-language.hh" +#include "../../hb-aat-layout.hh" +#include "../../hb-utf.hh" + + +namespace OT { + +template +inline unsigned int +hb_ot_name_convert_utf (hb_bytes_t bytes, + unsigned int *text_size /* IN/OUT */, + typename out_utf_t::codepoint_t *text /* OUT */) +{ + unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t); + const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ; + const typename in_utf_t::codepoint_t *src_end = src + src_len; + + typename out_utf_t::codepoint_t *dst = text; + + hb_codepoint_t unicode; + const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; + + if (text_size && *text_size) + { + (*text_size)--; /* Save room for NUL-termination. */ + const typename out_utf_t::codepoint_t *dst_end = text + *text_size; + + while (src < src_end && dst < dst_end) + { + const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement); + typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode); + if (dst_next == dst) + break; /* Out-of-room. */ + + dst = dst_next; + src = src_next; + } + + *text_size = dst - text; + *dst = 0; /* NUL-terminate. */ + } + + /* Accumulate length of rest. */ + unsigned int dst_len = dst - text; + while (src < src_end) + { + src = in_utf_t::next (src, src_end, &unicode, replacement); + dst_len += out_utf_t::encode_len (unicode); + } + return dst_len; +} + +#define entry_score var.u16[0] +#define entry_index var.u16[1] + + +/* + * name -- Naming + * https://docs.microsoft.com/en-us/typography/opentype/spec/name + */ +#define HB_OT_TAG_name HB_TAG('n','a','m','e') + +#define UNSUPPORTED 42 + +struct NameRecord +{ + hb_language_t language (hb_face_t *face) const + { +#ifndef HB_NO_OT_NAME_LANGUAGE + unsigned int p = platformID; + unsigned int l = languageID; + + if (p == 3) + return _hb_ot_name_language_for_ms_code (l); + + if (p == 1) + return _hb_ot_name_language_for_mac_code (l); + +#ifndef HB_NO_OT_NAME_LANGUAGE_AAT + if (p == 0) + return face->table.ltag->get_language (l); +#endif + +#endif + return HB_LANGUAGE_INVALID; + } + + uint16_t score () const + { + /* Same order as in cmap::find_best_subtable(). */ + unsigned int p = platformID; + unsigned int e = encodingID; + + /* 32-bit. */ + if (p == 3 && e == 10) return 0; + if (p == 0 && e == 6) return 1; + if (p == 0 && e == 4) return 2; + + /* 16-bit. */ + if (p == 3 && e == 1) return 3; + if (p == 0 && e == 3) return 4; + if (p == 0 && e == 2) return 5; + if (p == 0 && e == 1) return 6; + if (p == 0 && e == 0) return 7; + + /* Symbol. */ + if (p == 3 && e == 0) return 8; + + /* We treat all Mac Latin names as ASCII only. */ + if (p == 1 && e == 0) return 10; /* 10 is magic number :| */ + + return UNSUPPORTED; + } + + NameRecord* copy (hb_serialize_context_t *c, const void *base +#ifdef HB_EXPERIMENTAL_API + , const hb_hashmap_t *name_table_overrides +#endif + ) const + { + TRACE_SERIALIZE (this); + HB_UNUSED auto snap = c->snapshot (); + auto *out = c->embed (this); + if (unlikely (!out)) return_trace (nullptr); +#ifdef HB_EXPERIMENTAL_API + hb_ot_name_record_ids_t record_ids (platformID, encodingID, languageID, nameID); + hb_bytes_t* name_bytes; + + if (name_table_overrides->has (record_ids, &name_bytes)) { + hb_bytes_t encoded_bytes = *name_bytes; + char *name_str_utf16_be = nullptr; + + if (platformID != 1) + { + unsigned text_size = hb_ot_name_convert_utf (*name_bytes, nullptr, nullptr); + + text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf() + unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size; + name_str_utf16_be = (char *) hb_calloc (byte_len, 1); + if (!name_str_utf16_be) + { + c->revert (snap); + return_trace (nullptr); + } + hb_ot_name_convert_utf (*name_bytes, &text_size, + (hb_utf16_be_t::codepoint_t *) name_str_utf16_be); + + unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size; + if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) { + c->revert (snap); + hb_free (name_str_utf16_be); + return_trace (nullptr); + } + + encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len); + } + else + { + // mac platform, copy the UTF-8 string(all ascii characters) as is + if (!c->check_assign (out->length, encoded_bytes.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) { + c->revert (snap); + return_trace (nullptr); + } + } + + out->offset = 0; + c->push (); + encoded_bytes.copy (c); + c->add_link (out->offset, c->pop_pack (), hb_serialize_context_t::Tail, 0); + hb_free (name_str_utf16_be); + } + else +#endif + { + out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length); + } + return_trace (out); + } + + bool isUnicode () const + { + unsigned int p = platformID; + unsigned int e = encodingID; + + return (p == 0 || + (p == 3 && (e == 0 || e == 1 || e == 10))); + } + + static int cmp (const void *pa, const void *pb) + { + const NameRecord *a = (const NameRecord *)pa; + const NameRecord *b = (const NameRecord *)pb; + + if (a->platformID != b->platformID) + return a->platformID - b->platformID; + + if (a->encodingID != b->encodingID) + return a->encodingID - b->encodingID; + + if (a->languageID != b->languageID) + return a->languageID - b->languageID; + + if (a->nameID != b->nameID) + return a->nameID - b->nameID; + + if (a->length != b->length) + return a->length - b->length; + + return 0; + } + + bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && offset.sanitize (c, base, length)); + } + + HBUINT16 platformID; /* Platform ID. */ + HBUINT16 encodingID; /* Platform-specific encoding ID. */ + HBUINT16 languageID; /* Language ID. */ + HBUINT16 nameID; /* Name ID. */ + HBUINT16 length; /* String length (in bytes). */ + NNOffset16To> + offset; /* String offset from start of storage area (in bytes). */ + public: + DEFINE_SIZE_STATIC (12); +}; + +static int +_hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact) +{ + const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; + const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; + + /* Compare by name_id, then language. */ + + if (a->name_id != b->name_id) + return a->name_id - b->name_id; + + if (a->language == b->language) return 0; + if (!a->language) return -1; + if (!b->language) return +1; + + const char *astr = hb_language_to_string (a->language); + const char *bstr = hb_language_to_string (b->language); + + signed c = strcmp (astr, bstr); + + // 'a' is the user request, and 'b' is string in the font. + // If eg. user asks for "en-us" and font has "en", approve. + if (!exact && c && + hb_language_matches (b->language, a->language)) + return 0; + + return c; +} + +static int +_hb_ot_name_entry_cmp (const void *pa, const void *pb) +{ + /* Compare by name_id, then language, then score, then index. */ + + int v = _hb_ot_name_entry_cmp_key (pa, pb, true); + if (v) + return v; + + const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa; + const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb; + + if (a->entry_score != b->entry_score) + return a->entry_score - b->entry_score; + + if (a->entry_index != b->entry_index) + return a->entry_index - b->entry_index; + + return 0; +} + +struct name +{ + static constexpr hb_tag_t tableTag = HB_OT_TAG_name; + + unsigned int get_size () const + { return min_size + count * nameRecordZ.item_size; } + + template + bool serialize (hb_serialize_context_t *c, + Iterator it, + const void *src_string_pool +#ifdef HB_EXPERIMENTAL_API + , const hb_vector_t& insert_name_records + , const hb_hashmap_t *name_table_overrides +#endif + ) + { + TRACE_SERIALIZE (this); + + if (unlikely (!c->extend_min ((*this)))) return_trace (false); + + unsigned total_count = it.len () +#ifdef HB_EXPERIMENTAL_API + + insert_name_records.length +#endif + ; + this->format = 0; + if (!c->check_assign (this->count, total_count, HB_SERIALIZE_ERROR_INT_OVERFLOW)) + return false; + + NameRecord *name_records = (NameRecord *) hb_calloc (total_count, NameRecord::static_size); + if (unlikely (!name_records)) return_trace (false); + + hb_array_t records (name_records, total_count); + + for (const NameRecord& record : it) + { + hb_memcpy (name_records, &record, NameRecord::static_size); + name_records++; + } + +#ifdef HB_EXPERIMENTAL_API + for (unsigned i = 0; i < insert_name_records.length; i++) + { + const hb_ot_name_record_ids_t& ids = insert_name_records[i]; + NameRecord record; + record.platformID = ids.platform_id; + record.encodingID = ids.encoding_id; + record.languageID = ids.language_id; + record.nameID = ids.name_id; + record.length = 0; // handled in NameRecord copy() + record.offset = 0; + memcpy (name_records, &record, NameRecord::static_size); + name_records++; + } +#endif + + records.qsort (); + + c->copy_all (records, + src_string_pool +#ifdef HB_EXPERIMENTAL_API + , name_table_overrides +#endif + ); + hb_free (records.arrayZ); + + + if (unlikely (c->ran_out_of_room ())) return_trace (false); + + this->stringOffset = c->length (); + + return_trace (true); + } + + bool subset (hb_subset_context_t *c) const + { + TRACE_SUBSET (this); + + name *name_prime = c->serializer->start_embed (); + if (unlikely (!name_prime)) return_trace (false); + +#ifdef HB_EXPERIMENTAL_API + const hb_hashmap_t *name_table_overrides = + &c->plan->name_table_overrides; +#endif + + auto it = + + nameRecordZ.as_array (count) + | hb_filter (c->plan->name_ids, &NameRecord::nameID) + | hb_filter (c->plan->name_languages, &NameRecord::languageID) + | hb_filter ([&] (const NameRecord& namerecord) { + return + (c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY) + || namerecord.isUnicode (); + }) +#ifdef HB_EXPERIMENTAL_API + | hb_filter ([&] (const NameRecord& namerecord) { + if (name_table_overrides->is_empty ()) + return true; + hb_ot_name_record_ids_t rec_ids (namerecord.platformID, + namerecord.encodingID, + namerecord.languageID, + namerecord.nameID); + + hb_bytes_t *p; + if (name_table_overrides->has (rec_ids, &p) && + (*p).length == 0) + return false; + return true; + }) +#endif + ; + +#ifdef HB_EXPERIMENTAL_API + hb_hashmap_t retained_name_record_ids; + for (const NameRecord& rec : it) + { + hb_ot_name_record_ids_t rec_ids (rec.platformID, + rec.encodingID, + rec.languageID, + rec.nameID); + retained_name_record_ids.set (rec_ids, 1); + } + + hb_vector_t insert_name_records; + if (!name_table_overrides->is_empty ()) + { + if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true))) + return_trace (false); + for (const auto& record_ids : name_table_overrides->keys ()) + { + if (name_table_overrides->get (record_ids).length == 0) + continue; + if (retained_name_record_ids.has (record_ids)) + continue; + insert_name_records.push (record_ids); + } + } +#endif + + return (name_prime->serialize (c->serializer, it, + std::addressof (this + stringOffset) +#ifdef HB_EXPERIMENTAL_API + , insert_name_records + , name_table_overrides +#endif + )); + } + + bool sanitize_records (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + const void *string_pool = (this+stringOffset).arrayZ; + return_trace (nameRecordZ.sanitize (c, count, string_pool)); + } + + bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + likely (format == 0 || format == 1) && + c->check_array (nameRecordZ.arrayZ, count) && + c->check_range (this, stringOffset) && + sanitize_records (c)); + } + + struct accelerator_t + { + accelerator_t (hb_face_t *face) + { + this->table = hb_sanitize_context_t ().reference_table (face); + assert (this->table.get_length () >= this->table->stringOffset); + this->pool = (const char *) (const void *) (this->table+this->table->stringOffset); + this->pool_len = this->table.get_length () - this->table->stringOffset; + const hb_array_t all_names (this->table->nameRecordZ.arrayZ, + this->table->count); + + this->names.alloc (all_names.length, true); + + for (unsigned int i = 0; i < all_names.length; i++) + { + hb_ot_name_entry_t *entry = this->names.push (); + + entry->name_id = all_names[i].nameID; + entry->language = all_names[i].language (face); + entry->entry_score = all_names[i].score (); + entry->entry_index = i; + } + + this->names.qsort (_hb_ot_name_entry_cmp); + /* Walk and pick best only for each name_id,language pair, + * while dropping unsupported encodings. */ + unsigned int j = 0; + for (unsigned int i = 0; i < this->names.length; i++) + { + if (this->names[i].entry_score == UNSUPPORTED || + this->names[i].language == HB_LANGUAGE_INVALID) + continue; + if (i && + this->names[i - 1].name_id == this->names[i].name_id && + this->names[i - 1].language == this->names[i].language) + continue; + this->names[j++] = this->names[i]; + } + this->names.resize (j); + } + ~accelerator_t () + { + this->table.destroy (); + } + + int get_index (hb_ot_name_id_t name_id, + hb_language_t language, + unsigned int *width=nullptr) const + { + const hb_ot_name_entry_t key = {name_id, {0}, language}; + const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, + this->names.length, + sizeof (hb_ot_name_entry_t), + _hb_ot_name_entry_cmp_key, + true); + + if (!entry) + { + entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names, + this->names.length, + sizeof (hb_ot_name_entry_t), + _hb_ot_name_entry_cmp_key, + false); + } + + if (!entry) + return -1; + + if (width) + *width = entry->entry_score < 10 ? 2 : 1; + + return entry->entry_index; + } + + hb_bytes_t get_name (unsigned int idx) const + { + const hb_array_t all_names (table->nameRecordZ.arrayZ, table->count); + const NameRecord &record = all_names[idx]; + const hb_bytes_t string_pool (pool, pool_len); + return string_pool.sub_array (record.offset, record.length); + } + + private: + const char *pool; + unsigned int pool_len; + public: + hb_blob_ptr_t table; + hb_vector_t names; + }; + + public: + /* We only implement format 0 for now. */ + HBUINT16 format; /* Format selector (=0/1). */ + HBUINT16 count; /* Number of name records. */ + NNOffset16To> + stringOffset; /* Offset to start of string storage (from start of table). */ + UnsizedArrayOf + nameRecordZ; /* The name records where count is the number of records. */ + public: + DEFINE_SIZE_ARRAY (6, nameRecordZ); +}; + +#undef entry_index +#undef entry_score + +struct name_accelerator_t : name::accelerator_t { + name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {} +}; + +} /* namespace OT */ + + +#endif /* OT_NAME_NAME_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/UPDATING.txt b/src/java.desktop/share/native/libharfbuzz/UPDATING.txt index 34434ddef04..8beacde4b61 100644 --- a/src/java.desktop/share/native/libharfbuzz/UPDATING.txt +++ b/src/java.desktop/share/native/libharfbuzz/UPDATING.txt @@ -1,53 +1,118 @@ Tips and tasks when updating harfbuzz sources to a newer version. ----------------------------------------------------------------- +STEP 1: UPDATING FILES +---------------------- +Download and unzip the latest version from https://github.com/harfbuzz/harfbuzz/releases We only use files from the src directory and even then only the ones we need. So just C++ include and source files and only the ones needed for the library, -and even then just the ones we use. Do NOT just copy everything. +and even then just the ones we use. +IMPORTANT! DO NOT just copy everything. -So one way to update is to - -- copy over from the updated harfbuzz the exact same files we already have -- it isn't a flat directory so watch out for that -- any that are no longer available (copy fails) we remove but these may come - back later if they were actually renamed -- look for files in the destination that were NOT updated - perhaps they - are gone in the upstream - or renamed. Remove them if they are really - obsolete, or add their replacements/renames. -- iterate over : build and see what new file is missing that causes a build failure -- when this is done we have something buildable -- make sure it builds on all supported platforms. -- Harfbuzz is not modular so it is not easy, +- Harfbuzz is not modular, so the update is not a straightforward process. - The main thing is we do NOT want any * "test" programs (test in the name, have a main are clues) * support for (eg) GLib, DirectWrite, Graphite, GDI, ICU, Uniscribe * aggregators like harfbuzz.cc - since it includes things from the above as well as hb-ft.cc which we specifically exclude in the Makefile - * but we do use core text support on macOS. - * I really wish that "src" were just library source but I expect the authors + * but we do use core text support on macOS. + * I really wish that "src" were just library source, but I expect the authors have their reasons. -- we do not apply any header file changes so this is not an issue +So one way to update is to + +- copy over from the updated harfbuzz the exact same files we already have +- it isn't a flat directory so watch out for that. + +- For files that are no longer available (for which copy fails), we remove such files, + but these may come back later if they were actually renamed. + +- look for files in the destination that were NOT updated - perhaps they + are removed or renamed in the upstream. Remove them if they are really + obsolete, or add their replacements/renames. + In IntelliJ IDE: + Newly added files are shown in RED + Modified in BLUE + NOT Updated in WHITE + This feature might be helpful to keep track of new, modified and unchanged files. + + +STEP 2: BUILD CHANGES INCREMENTALLY +----------------------------------- +- iterate over : build and see what new file is missing that causes a build failure. + Sometimes just running a build does not show up any failures due to stale files. + Clean followed by build would be helpful in this situation. + +- You might run into compiler warnings that are treated as errors or the requirement + to set certain compiler flags if the build fails on a specific platform. + Check "COMPILER WARNINGS AND SETTING FLAGS" section for more details. + +- when this is done we have something buildable, make sure it builds + on all supported platforms. + + +STEP 3: COMPILER WARNINGS AND SETTING FLAGS +------------------------------------------- +- Update make parameters in Awt2DLibraries.gmk + Since we don't use configure we need to manually specify the options + we need in the Harfbuzz section of Awt2DLibraries.gmk. + As well as adding new options, we may need to clean up obsolete options. + Note there may be platform variations in the flags. + +- As with other 3rd party libs we do not fix the code to eliminate compiler + warnings unless they are critical and clearly avoiding a bug. Even then + we'd report it upstream and apply the patch once it is made available. + The usual practice is do just disable the warnings. + + +STEP 4: UPDATING .md FILE +------------------------- +- we do not apply any header file changes so this is not an issue. + - verify the license text is unchanged (extra steps are needed if it is) and update - src/java.desktop/share/legal/harfbuzz.md with the new version + src/java.desktop/share/legal/harfbuzz.md with the new version. + + +STEP 5: REPLACE TABS & REMOVE TRAILING SPACES +--------------------------------------------- - clean up trailing white space and tabs to follow jcheck rules. Use "expand" and "sed" to remove tabs and trailing white space from the imported sources. -- test using all the automated jtreg tests on all platforms -- do manual verification of Arabic, Hebrew, Thai, Indic against previous releases. - Look for manual related layout jtreg tests and run on Windows,Linux and Mac. + To clean up the extra spaces and tabs run the following script at + each folder level within libharfbuzz. + + for f in *.c *.h *.cc *.hh; + do + # replace tabs with spaces + expand ${f} > ${f}.tmp; + mv ${f}.tmp $f; + + # fix line endings to LF + sed -e 's/\r$//g' ${f} > ${f}.tmp; + mv ${f}.tmp $f; + + # remove trailing spaces + sed -e 's/[ ]* $//g' ${f} > ${f}.tmp; + mv ${f}.tmp $f; + done + + +STEP 6: TESTING +--------------- +- test using all the automated jtreg tests on all platforms. + +- do MANUAL verification of Arabic, Hebrew, Thai, Indic against previous releases. + Look for manual related layout jtreg tests (test/jdk/java/awt/font/TextLayout) + and run on Windows,Linux and Mac. Use Font2DTest set to TextLayout and check the above languages. Probably not going to see layout problems a code point at a time but it needs to be checked. -- Update make parameters as needed - Since we don't use configure we need to manually specify the options - we need in the harfbuzz section of Awt2DLibraries.gmk. - As well as adding new options, we may need to clean up obsolete options. - Note there may be platform variations in the flags. + Different unicode combinations can be checked using Font2DTest. + Run Font2DTest, select 'UserText' option for 'Text to use'. + Paste unicodes of different languages (Arabic, Hebrew, Thai, Indic) + and compare the glyphs with previous versions. + It should look the same in both cases. -- As with other 3rd party libs we do not fix the code to eliminate compiler - warnings unless they are critical and clearly avoiding a bug. Even then - we'd report it upstream. The usual practice is do just disable the warnings -- Update THIS UPDATING.txt file too if it is outdated. +- FINALLY, Do update THIS UPDATING.txt file too if it is outdated. diff --git a/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh new file mode 100644 index 00000000000..c2e24a70678 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/graph/classdef-graph.hh @@ -0,0 +1,216 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include "graph.hh" +#include "../hb-ot-layout-common.hh" + +#ifndef GRAPH_CLASSDEF_GRAPH_HH +#define GRAPH_CLASSDEF_GRAPH_HH + +namespace graph { + +struct ClassDefFormat1 : public OT::ClassDefFormat1_3 +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + constexpr unsigned min_size = OT::ClassDefFormat1_3::min_size; + if (vertex_len < min_size) return false; + return vertex_len >= min_size + classValue.get_size () - classValue.len.get_size (); + } +}; + +struct ClassDefFormat2 : public OT::ClassDefFormat2_4 +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + constexpr unsigned min_size = OT::ClassDefFormat2_4::min_size; + if (vertex_len < min_size) return false; + return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size (); + } +}; + +struct ClassDef : public OT::ClassDef +{ + template + static bool add_class_def (gsubgpos_graph_context_t& c, + unsigned parent_id, + unsigned link_position, + It glyph_and_class, + unsigned max_size) + { + unsigned class_def_prime_id = c.graph.new_node (nullptr, nullptr); + auto& class_def_prime_vertex = c.graph.vertices_[class_def_prime_id]; + if (!make_class_def (c, glyph_and_class, class_def_prime_id, max_size)) + return false; + + auto* class_def_link = c.graph.vertices_[parent_id].obj.real_links.push (); + class_def_link->width = SmallTypes::size; + class_def_link->objidx = class_def_prime_id; + class_def_link->position = link_position; + class_def_prime_vertex.parents.push (parent_id); + + return true; + } + + template + static bool make_class_def (gsubgpos_graph_context_t& c, + It glyph_and_class, + unsigned dest_obj, + unsigned max_size) + { + char* buffer = (char*) hb_calloc (1, max_size); + hb_serialize_context_t serializer (buffer, max_size); + OT::ClassDef_serialize (&serializer, glyph_and_class); + serializer.end_serialize (); + if (serializer.in_error ()) + { + hb_free (buffer); + return false; + } + + hb_bytes_t class_def_copy = serializer.copy_bytes (); + c.add_buffer ((char *) class_def_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer. + + auto& obj = c.graph.vertices_[dest_obj].obj; + obj.head = (char *) class_def_copy.arrayZ; + obj.tail = obj.head + class_def_copy.length; + + hb_free (buffer); + return true; + } + + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < OT::ClassDef::min_size) return false; + switch (u.format) + { + case 1: return ((ClassDefFormat1*)this)->sanitize (vertex); + case 2: return ((ClassDefFormat2*)this)->sanitize (vertex); +#ifndef HB_NO_BEYOND_64K + // Not currently supported + case 3: + case 4: +#endif + default: return false; + } + } +}; + + +struct class_def_size_estimator_t +{ + template + class_def_size_estimator_t (It glyph_and_class) + : gids_consecutive (true), num_ranges_per_class (), glyphs_per_class () + { + unsigned last_gid = (unsigned) -1; + for (auto p : + glyph_and_class) + { + unsigned gid = p.first; + unsigned klass = p.second; + + if (last_gid != (unsigned) -1 && gid != last_gid + 1) + gids_consecutive = false; + last_gid = gid; + + hb_set_t* glyphs; + if (glyphs_per_class.has (klass, &glyphs) && glyphs) { + glyphs->add (gid); + continue; + } + + hb_set_t new_glyphs; + new_glyphs.add (gid); + glyphs_per_class.set (klass, std::move (new_glyphs)); + } + + if (in_error ()) return; + + for (unsigned klass : glyphs_per_class.keys ()) + { + if (!klass) continue; // class 0 doesn't get encoded. + + const hb_set_t& glyphs = glyphs_per_class.get (klass); + hb_codepoint_t start = HB_SET_VALUE_INVALID; + hb_codepoint_t end = HB_SET_VALUE_INVALID; + + unsigned count = 0; + while (glyphs.next_range (&start, &end)) + count++; + + num_ranges_per_class.set (klass, count); + } + } + + // Incremental increase in the Coverage and ClassDef table size + // (worst case) if all glyphs associated with 'klass' were added. + unsigned incremental_coverage_size (unsigned klass) const + { + // Coverage takes 2 bytes per glyph worst case, + return 2 * glyphs_per_class.get (klass).get_population (); + } + + // Incremental increase in the Coverage and ClassDef table size + // (worst case) if all glyphs associated with 'klass' were added. + unsigned incremental_class_def_size (unsigned klass) const + { + // ClassDef takes 6 bytes per range + unsigned class_def_2_size = 6 * num_ranges_per_class.get (klass); + if (gids_consecutive) + { + // ClassDef1 takes 2 bytes per glyph, but only can be used + // when gids are consecutive. + return hb_min (2 * glyphs_per_class.get (klass).get_population (), class_def_2_size); + } + + return class_def_2_size; + } + + bool in_error () + { + if (num_ranges_per_class.in_error ()) return true; + if (glyphs_per_class.in_error ()) return true; + + for (const hb_set_t& s : glyphs_per_class.values ()) + { + if (s.in_error ()) return true; + } + return false; + } + + private: + bool gids_consecutive; + hb_hashmap_t num_ranges_per_class; + hb_hashmap_t glyphs_per_class; +}; + + +} + +#endif // GRAPH_CLASSDEF_GRAPH_HH diff --git a/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh new file mode 100644 index 00000000000..49d09363156 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/graph/coverage-graph.hh @@ -0,0 +1,152 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include "graph.hh" +#include "../OT/Layout/Common/Coverage.hh" + +#ifndef GRAPH_COVERAGE_GRAPH_HH +#define GRAPH_COVERAGE_GRAPH_HH + +namespace graph { + +struct CoverageFormat1 : public OT::Layout::Common::CoverageFormat1_3 +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + constexpr unsigned min_size = OT::Layout::Common::CoverageFormat1_3::min_size; + if (vertex_len < min_size) return false; + return vertex_len >= min_size + glyphArray.get_size () - glyphArray.len.get_size (); + } +}; + +struct CoverageFormat2 : public OT::Layout::Common::CoverageFormat2_4 +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + constexpr unsigned min_size = OT::Layout::Common::CoverageFormat2_4::min_size; + if (vertex_len < min_size) return false; + return vertex_len >= min_size + rangeRecord.get_size () - rangeRecord.len.get_size (); + } +}; + +struct Coverage : public OT::Layout::Common::Coverage +{ + static Coverage* clone_coverage (gsubgpos_graph_context_t& c, + unsigned coverage_id, + unsigned new_parent_id, + unsigned link_position, + unsigned start, unsigned end) + + { + unsigned coverage_size = c.graph.vertices_[coverage_id].table_size (); + auto& coverage_v = c.graph.vertices_[coverage_id]; + Coverage* coverage_table = (Coverage*) coverage_v.obj.head; + if (!coverage_table || !coverage_table->sanitize (coverage_v)) + return nullptr; + + auto new_coverage = + + hb_zip (coverage_table->iter (), hb_range ()) + | hb_filter ([&] (hb_pair_t p) { + return p.second >= start && p.second < end; + }) + | hb_map_retains_sorting (hb_first) + ; + + return add_coverage (c, new_parent_id, link_position, new_coverage, coverage_size); + } + + template + static Coverage* add_coverage (gsubgpos_graph_context_t& c, + unsigned parent_id, + unsigned link_position, + It glyphs, + unsigned max_size) + { + unsigned coverage_prime_id = c.graph.new_node (nullptr, nullptr); + auto& coverage_prime_vertex = c.graph.vertices_[coverage_prime_id]; + if (!make_coverage (c, glyphs, coverage_prime_id, max_size)) + return nullptr; + + auto* coverage_link = c.graph.vertices_[parent_id].obj.real_links.push (); + coverage_link->width = SmallTypes::size; + coverage_link->objidx = coverage_prime_id; + coverage_link->position = link_position; + coverage_prime_vertex.parents.push (parent_id); + + return (Coverage*) coverage_prime_vertex.obj.head; + } + + template + static bool make_coverage (gsubgpos_graph_context_t& c, + It glyphs, + unsigned dest_obj, + unsigned max_size) + { + char* buffer = (char*) hb_calloc (1, max_size); + hb_serialize_context_t serializer (buffer, max_size); + OT::Layout::Common::Coverage_serialize (&serializer, glyphs); + serializer.end_serialize (); + if (serializer.in_error ()) + { + hb_free (buffer); + return false; + } + + hb_bytes_t coverage_copy = serializer.copy_bytes (); + c.add_buffer ((char *) coverage_copy.arrayZ); // Give ownership to the context, it will cleanup the buffer. + + auto& obj = c.graph.vertices_[dest_obj].obj; + obj.head = (char *) coverage_copy.arrayZ; + obj.tail = obj.head + coverage_copy.length; + + hb_free (buffer); + return true; + } + + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < OT::Layout::Common::Coverage::min_size) return false; + switch (u.format) + { + case 1: return ((CoverageFormat1*)this)->sanitize (vertex); + case 2: return ((CoverageFormat2*)this)->sanitize (vertex); +#ifndef HB_NO_BEYOND_64K + // Not currently supported + case 3: + case 4: +#endif + default: return false; + } + } +}; + + +} + +#endif // GRAPH_COVERAGE_GRAPH_HH diff --git a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh index 52ca9dd142e..38ca5db0961 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/graph.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/graph.hh @@ -24,6 +24,10 @@ * Google Author(s): Garret Rieger */ +#include "../hb-set.hh" +#include "../hb-priority-queue.hh" +#include "../hb-serialize.hh" + #ifndef GRAPH_GRAPH_HH #define GRAPH_GRAPH_HH @@ -45,6 +49,95 @@ struct graph_t unsigned end = 0; unsigned priority = 0; + + bool link_positions_valid (unsigned num_objects, bool removed_nil) + { + hb_set_t assigned_bytes; + for (const auto& l : obj.real_links) + { + if (l.objidx >= num_objects + || (removed_nil && !l.objidx)) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Invalid object index."); + return false; + } + + unsigned start = l.position; + unsigned end = start + l.width - 1; + + if (unlikely (l.width < 2 || l.width > 4)) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Invalid link width."); + return false; + } + + if (unlikely (end >= table_size ())) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Link position is out of bounds."); + return false; + } + + if (unlikely (assigned_bytes.intersects (start, end))) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Invalid graph. Found offsets whose positions overlap."); + return false; + } + + assigned_bytes.add_range (start, end); + } + + return !assigned_bytes.in_error (); + } + + void normalize () + { + obj.real_links.qsort (); + for (auto& l : obj.real_links) + { + for (unsigned i = 0; i < l.width; i++) + { + obj.head[l.position + i] = 0; + } + } + } + + bool equals (const vertex_t& other, + const graph_t& graph, + const graph_t& other_graph, + unsigned depth) const + { + if (!(as_bytes () == other.as_bytes ())) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + "vertex [%lu] bytes != [%lu] bytes, depth = %u", + (unsigned long) table_size (), + (unsigned long) other.table_size (), + depth); + + auto a = as_bytes (); + auto b = other.as_bytes (); + while (a || b) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " 0x%x %s 0x%x", (unsigned) *a, (*a == *b) ? "==" : "!=", (unsigned) *b); + a++; + b++; + } + return false; + } + + return links_equal (obj.real_links, other.obj.real_links, graph, other_graph, depth); + } + + hb_bytes_t as_bytes () const + { + return hb_bytes_t (obj.head, table_size ()); + } + friend void swap (vertex_t& a, vertex_t& b) { hb_swap (a.obj, b.obj); @@ -56,6 +149,18 @@ struct graph_t hb_swap (a.priority, b.priority); } + hb_hashmap_t + position_to_index_map () const + { + hb_hashmap_t result; + + for (const auto& l : obj.real_links) { + result.set (l.position, l.objidx); + } + + return result; + } + bool is_shared () const { return parents.length > 1; @@ -71,11 +176,27 @@ struct graph_t for (unsigned i = 0; i < parents.length; i++) { if (parents[i] != parent_index) continue; - parents.remove (i); + parents.remove_unordered (i); break; } } + void remove_real_link (unsigned child_index, const void* offset) + { + for (unsigned i = 0; i < obj.real_links.length; i++) + { + auto& link = obj.real_links.arrayZ[i]; + if (link.objidx != child_index) + continue; + + if ((obj.head + link.position) != offset) + continue; + + obj.real_links.remove_unordered (i); + return; + } + } + void remap_parents (const hb_vector_t& id_map) { for (unsigned i = 0; i < parents.length; i++) @@ -107,6 +228,10 @@ struct graph_t return priority >= 3; } + size_t table_size () const { + return obj.tail - obj.head; + } + int64_t modified_distance (unsigned order) const { // TODO(garretrieger): once priority is high enough, should try @@ -131,6 +256,57 @@ struct graph_t return -table_size; } + + private: + bool links_equal (const hb_vector_t& this_links, + const hb_vector_t& other_links, + const graph_t& graph, + const graph_t& other_graph, + unsigned depth) const + { + auto a = this_links.iter (); + auto b = other_links.iter (); + + while (a && b) + { + const auto& link_a = *a; + const auto& link_b = *b; + + if (link_a.width != link_b.width || + link_a.is_signed != link_b.is_signed || + link_a.whence != link_b.whence || + link_a.position != link_b.position || + link_a.bias != link_b.bias) + return false; + + if (!graph.vertices_[link_a.objidx].equals ( + other_graph.vertices_[link_b.objidx], graph, other_graph, depth + 1)) + return false; + + a++; + b++; + } + + if (bool (a) != bool (b)) + return false; + + return true; + } + }; + + template + struct vertex_and_table_t + { + vertex_and_table_t () : index (0), vertex (nullptr), table (nullptr) + {} + + unsigned index; + vertex_t* vertex; + T* table; + + operator bool () { + return table && vertex; + } }; /* @@ -145,7 +321,8 @@ struct graph_t : parents_invalid (true), distance_invalid (true), positions_invalid (true), - successful (true) + successful (true), + buffers () { num_roots_for_space_.push (1); bool removed_nil = false; @@ -153,8 +330,6 @@ struct graph_t vertices_scratch_.alloc (objects.length); for (unsigned i = 0; i < objects.length; i++) { - // TODO(grieger): check all links point to valid objects. - // If this graph came from a serialization buffer object 0 is the // nil object. We don't need it for our purposes here so drop it. if (i == 0 && !objects[i]) @@ -166,6 +341,9 @@ struct graph_t vertex_t* v = vertices_.push (); if (check_success (!vertices_.in_error ())) v->obj = *objects[i]; + + check_success (v->link_positions_valid (objects.length, removed_nil)); + if (!removed_nil) continue; // Fix indices to account for removed nil object. for (auto& l : v->obj.all_links_writer ()) { @@ -177,6 +355,20 @@ struct graph_t ~graph_t () { vertices_.fini (); + for (char* b : buffers) + hb_free (b); + } + + bool operator== (const graph_t& other) const + { + return root ().equals (other.root (), *this, other, 0); + } + + // Sorts links of all objects in a consistent manner and zeroes all offsets. + void normalize () + { + for (auto& v : vertices_.writer ()) + v.normalize (); } bool in_error () const @@ -199,11 +391,43 @@ struct graph_t return vertices_.length - 1; } - const hb_serialize_context_t::object_t& object(unsigned i) const + const hb_serialize_context_t::object_t& object (unsigned i) const { return vertices_[i].obj; } + void add_buffer (char* buffer) + { + buffers.push (buffer); + } + + /* + * Adds a 16 bit link from parent_id to child_id + */ + template + void add_link (T* offset, + unsigned parent_id, + unsigned child_id) + { + auto& v = vertices_[parent_id]; + auto* link = v.obj.real_links.push (); + link->width = 2; + link->objidx = child_id; + link->position = (char*) offset - (char*) v.obj.head; + vertices_[child_id].parents.push (parent_id); + } + + /* + * Generates a new topological sorting of graph ordered by the shortest + * distance to each node if positions are marked as invalid. + */ + void sort_shortest_distance_if_needed () + { + if (!positions_invalid) return; + sort_shortest_distance (); + } + + /* * Generates a new topological sorting of graph ordered by the shortest * distance to each node. @@ -239,6 +463,13 @@ struct graph_t hb_swap (sorted_graph[new_id], vertices_[next_id]); const vertex_t& next = sorted_graph[new_id]; + if (unlikely (!check_success(new_id >= 0))) { + // We are out of ids. Which means we've visited a node more than once. + // This graph contains a cycle which is not allowed. + DEBUG_MSG (SUBSET_REPACK, nullptr, "Invalid graph. Contains cycle."); + return; + } + id_map[next_id] = new_id--; for (const auto& link : next.obj.all_links ()) { @@ -256,44 +487,152 @@ struct graph_t check_success (!queue.in_error ()); check_success (!sorted_graph.in_error ()); - if (!check_success (new_id == -1)) - print_orphaned_nodes (); remap_all_obj_indices (id_map, &sorted_graph); - hb_swap (vertices_, sorted_graph); + + if (!check_success (new_id == -1)) + print_orphaned_nodes (); } /* - * Assign unique space numbers to each connected subgraph of 32 bit offset(s). + * Finds the set of nodes (placed into roots) that should be assigned unique spaces. + * More specifically this looks for the top most 24 bit or 32 bit links in the graph. + * Some special casing is done that is specific to the layout of GSUB/GPOS tables. */ - bool assign_32bit_spaces () + void find_space_roots (hb_set_t& visited, hb_set_t& roots) { - unsigned root_index = root_idx (); - hb_set_t visited; - hb_set_t roots; - for (unsigned i = 0; i <= root_index; i++) + int root_index = (int) root_idx (); + for (int i = root_index; i >= 0; i--) { + if (visited.has (i)) continue; + // Only real links can form 32 bit spaces for (auto& l : vertices_[i].obj.real_links) { - if (l.width == 4 && !l.is_signed) + if (l.is_signed || l.width < 3) + continue; + + if (i == root_index && l.width == 3) + // Ignore 24bit links from the root node, this skips past the single 24bit + // pointer to the lookup list. + continue; + + if (l.width == 3) { - roots.add (l.objidx); - find_subgraph (l.objidx, visited); + // A 24bit offset forms a root, unless there is 32bit offsets somewhere + // in it's subgraph, then those become the roots instead. This is to make sure + // that extension subtables beneath a 24bit lookup become the spaces instead + // of the offset to the lookup. + hb_set_t sub_roots; + find_32bit_roots (l.objidx, sub_roots); + if (sub_roots) { + for (unsigned sub_root_idx : sub_roots) { + roots.add (sub_root_idx); + find_subgraph (sub_root_idx, visited); + } + continue; + } } + + roots.add (l.objidx); + find_subgraph (l.objidx, visited); } } + } - // Mark everything not in the subgraphs of 32 bit roots as visited. - // This prevents 32 bit subgraphs from being connected via nodes not in the 32 bit subgraphs. + template + vertex_and_table_t as_table (unsigned parent, const void* offset, Ts... ds) + { + return as_table_from_index (index_for_offset (parent, offset), std::forward(ds)...); + } + + template + vertex_and_table_t as_mutable_table (unsigned parent, const void* offset, Ts... ds) + { + return as_table_from_index (mutable_index_for_offset (parent, offset), std::forward(ds)...); + } + + template + vertex_and_table_t as_table_from_index (unsigned index, Ts... ds) + { + if (index >= vertices_.length) + return vertex_and_table_t (); + + vertex_and_table_t r; + r.vertex = &vertices_[index]; + r.table = (T*) r.vertex->obj.head; + r.index = index; + if (!r.table) + return vertex_and_table_t (); + + if (!r.table->sanitize (*(r.vertex), std::forward(ds)...)) + return vertex_and_table_t (); + + return r; + } + + // Finds the object id of the object pointed to by the offset at 'offset' + // within object[node_idx]. + unsigned index_for_offset (unsigned node_idx, const void* offset) const + { + const auto& node = object (node_idx); + if (offset < node.head || offset >= node.tail) return -1; + + unsigned length = node.real_links.length; + for (unsigned i = 0; i < length; i++) + { + // Use direct access for increased performance, this is a hot method. + const auto& link = node.real_links.arrayZ[i]; + if (offset != node.head + link.position) + continue; + return link.objidx; + } + + return -1; + } + + // Finds the object id of the object pointed to by the offset at 'offset' + // within object[node_idx]. Ensures that the returned object is safe to mutate. + // That is, if the original child object is shared by parents other than node_idx + // it will be duplicated and the duplicate will be returned instead. + unsigned mutable_index_for_offset (unsigned node_idx, const void* offset) + { + unsigned child_idx = index_for_offset (node_idx, offset); + auto& child = vertices_[child_idx]; + for (unsigned p : child.parents) + { + if (p != node_idx) { + return duplicate (node_idx, child_idx); + } + } + + return child_idx; + } + + + /* + * Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s). + * Currently, this is implemented specifically tailored to the structure of a GPOS/GSUB + * (including with 24bit offsets) table. + */ + bool assign_spaces () + { + update_parents (); + + hb_set_t visited; + hb_set_t roots; + find_space_roots (visited, roots); + + // Mark everything not in the subgraphs of the roots as visited. This prevents + // subgraphs from being connected via nodes not in those subgraphs. visited.invert (); if (!roots) return false; while (roots) { - unsigned next = HB_SET_VALUE_INVALID; + uint32_t next = HB_SET_VALUE_INVALID; if (unlikely (!check_success (!roots.in_error ()))) break; if (!roots.next (&next)) break; @@ -361,6 +700,9 @@ struct graph_t } } + if (in_error ()) + return false; + if (!made_changes) return false; @@ -374,8 +716,8 @@ struct graph_t auto new_subgraph = + subgraph.keys () - | hb_map([&] (unsigned node_idx) { - const unsigned *v; + | hb_map([&] (uint32_t node_idx) { + const uint32_t *v; if (index_map.has (node_idx, &v)) return *v; return node_idx; }) @@ -385,10 +727,10 @@ struct graph_t remap_obj_indices (index_map, parents.iter (), true); // Update roots set with new indices as needed. - unsigned next = HB_SET_VALUE_INVALID; + uint32_t next = HB_SET_VALUE_INVALID; while (roots.next (&next)) { - const unsigned *v; + const uint32_t *v; if (index_map.has (next, &v)) { roots.del (next); @@ -403,7 +745,7 @@ struct graph_t { for (const auto& link : vertices_[node_idx].obj.all_links ()) { - const unsigned *v; + const uint32_t *v; if (subgraph.has (link.objidx, &v)) { subgraph.set (link.objidx, *v + 1); @@ -422,6 +764,68 @@ struct graph_t find_subgraph (link.objidx, subgraph); } + size_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph, unsigned max_depth = -1) + { + if (subgraph.has (node_idx)) return 0; + subgraph.add (node_idx); + + const auto& o = vertices_[node_idx].obj; + size_t size = o.tail - o.head; + if (max_depth == 0) + return size; + + for (const auto& link : o.all_links ()) + size += find_subgraph_size (link.objidx, subgraph, max_depth - 1); + return size; + } + + /* + * Finds the topmost children of 32bit offsets in the subgraph starting + * at node_idx. Found indices are placed into 'found'. + */ + void find_32bit_roots (unsigned node_idx, hb_set_t& found) + { + for (const auto& link : vertices_[node_idx].obj.all_links ()) + { + if (!link.is_signed && link.width == 4) { + found.add (link.objidx); + continue; + } + find_32bit_roots (link.objidx, found); + } + } + + /* + * Moves the child of old_parent_idx pointed to by old_offset to a new + * vertex at the new_offset. + */ + template + void move_child (unsigned old_parent_idx, + const O* old_offset, + unsigned new_parent_idx, + const O* new_offset) + { + distance_invalid = true; + positions_invalid = true; + + auto& old_v = vertices_[old_parent_idx]; + auto& new_v = vertices_[new_parent_idx]; + + unsigned child_id = index_for_offset (old_parent_idx, + old_offset); + + auto* new_link = new_v.obj.real_links.push (); + new_link->width = O::static_size; + new_link->objidx = child_id; + new_link->position = (const char*) new_offset - (const char*) new_v.obj.head; + + auto& child = vertices_[child_id]; + child.parents.push (new_parent_idx); + + old_v.remove_real_link (child_id, old_offset); + child.remove_parent (old_parent_idx); + } + /* * duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign * links. index_map is updated with mappings from old id to new id. If a duplication has already @@ -432,7 +836,11 @@ struct graph_t if (index_map.has (node_idx)) return; - index_map.set (node_idx, duplicate (node_idx)); + unsigned clone_idx = duplicate (node_idx); + if (!check_success (clone_idx != (unsigned) -1)) + return; + + index_map.set (node_idx, clone_idx); for (const auto& l : object (node_idx).all_links ()) { duplicate_subgraph (l.objidx, index_map); } @@ -490,7 +898,20 @@ struct graph_t * parent to the clone. The copy is a shallow copy, objects * linked from child are not duplicated. */ - bool duplicate (unsigned parent_idx, unsigned child_idx) + unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx) + { + unsigned new_idx = duplicate (parent_idx, child_idx); + if (new_idx == (unsigned) -1) return child_idx; + return new_idx; + } + + + /* + * Creates a copy of child and re-assigns the link from + * parent to the clone. The copy is a shallow copy, objects + * linked from child are not duplicated. + */ + unsigned duplicate (unsigned parent_idx, unsigned child_idx) { update_parents (); @@ -504,12 +925,12 @@ struct graph_t { // Can't duplicate this node, doing so would orphan the original one as all remaining links // to child are from parent. - DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d", + DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %u => %u", parent_idx, child_idx); - return false; + return -1; } - DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d", + DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %u => %u", parent_idx, child_idx); unsigned clone_idx = duplicate (child_idx); @@ -526,7 +947,40 @@ struct graph_t reassign_link (l, parent_idx, clone_idx); } - return true; + return clone_idx; + } + + + /* + * Adds a new node to the graph, not connected to anything. + */ + unsigned new_node (char* head, char* tail) + { + positions_invalid = true; + distance_invalid = true; + + auto* clone = vertices_.push (); + if (vertices_.in_error ()) { + return -1; + } + + clone->obj.head = head; + clone->obj.tail = tail; + clone->distance = 0; + clone->space = 0; + + unsigned clone_idx = vertices_.length - 2; + + // The last object is the root of the graph, so swap back the root to the end. + // The root's obj idx does change, however since it's root nothing else refers to it. + // all other obj idx's will be unaffected. + hb_swap (vertices_[vertices_.length - 2], *clone); + + // Since the root moved, update the parents arrays of all children on the root. + for (const auto& l : root ().obj.all_links ()) + vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ()); + + return clone_idx; } /* @@ -534,7 +988,7 @@ struct graph_t */ bool raise_childrens_priority (unsigned parent_idx) { - DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d", + DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %u", parent_idx); // This operation doesn't change ordering until a sort is run, so no need // to invalidate positions. It does not change graph structure so no need @@ -546,6 +1000,72 @@ struct graph_t return made_change; } + bool is_fully_connected () + { + update_parents(); + + if (root().parents) + // Root cannot have parents. + return false; + + for (unsigned i = 0; i < root_idx (); i++) + { + if (!vertices_[i].parents) + return false; + } + return true; + } + +#if 0 + /* + * Saves the current graph to a packed binary format which the repacker fuzzer takes + * as a seed. + */ + void save_fuzzer_seed (hb_tag_t tag) const + { + FILE* f = fopen ("./repacker_fuzzer_seed", "w"); + fwrite ((void*) &tag, sizeof (tag), 1, f); + + uint16_t num_objects = vertices_.length; + fwrite ((void*) &num_objects, sizeof (num_objects), 1, f); + + for (const auto& v : vertices_) + { + uint16_t blob_size = v.table_size (); + fwrite ((void*) &blob_size, sizeof (blob_size), 1, f); + fwrite ((const void*) v.obj.head, blob_size, 1, f); + } + + uint16_t link_count = 0; + for (const auto& v : vertices_) + link_count += v.obj.real_links.length; + + fwrite ((void*) &link_count, sizeof (link_count), 1, f); + + typedef struct + { + uint16_t parent; + uint16_t child; + uint16_t position; + uint8_t width; + } link_t; + + for (unsigned i = 0; i < vertices_.length; i++) + { + for (const auto& l : vertices_[i].obj.real_links) + { + link_t link { + (uint16_t) i, (uint16_t) l.objidx, + (uint16_t) l.position, (uint8_t) l.width + }; + fwrite ((void*) &link, sizeof (link), 1, f); + } + } + + fclose (f); + } +#endif + void print_orphaned_nodes () { if (!DEBUG_ENABLED(SUBSET_REPACK)) return; @@ -554,6 +1074,10 @@ struct graph_t parents_invalid = true; update_parents(); + if (root().parents) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Root node has incoming edges."); + } + for (unsigned i = 0; i < root_idx (); i++) { const auto& v = vertices_[i]; @@ -622,7 +1146,7 @@ struct graph_t private: /* - * Returns the numbers of incoming edges that are 32bits wide. + * Returns the numbers of incoming edges that are 24 or 32 bits wide. */ unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const { @@ -636,7 +1160,9 @@ struct graph_t // Only real links can be wide for (const auto& l : vertices_[p].obj.real_links) { - if (l.objidx == node_idx && l.width == 4 && !l.is_signed) + if (l.objidx == node_idx + && (l.width == 3 || l.width == 4) + && !l.is_signed) { count++; parents.add (p); @@ -668,6 +1194,11 @@ struct graph_t } } + for (unsigned i = 0; i < vertices_.length; i++) + // parents arrays must be accurate or downstream operations like cycle detection + // and sorting won't work correctly. + check_success (!vertices_[i].parents.in_error ()); + parents_invalid = false; } @@ -786,7 +1317,7 @@ struct graph_t { for (auto& link : vertices_[i].obj.all_links_writer ()) { - const unsigned *v; + const uint32_t *v; if (!id_map.has (link.objidx, &v)) continue; if (only_wide && !(link.width == 4 && !link.is_signed)) continue; @@ -853,6 +1384,7 @@ struct graph_t bool positions_invalid; bool successful; hb_vector_t num_roots_for_space_; + hb_vector_t buffers; }; } diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc new file mode 100644 index 00000000000..b2044426d46 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.cc @@ -0,0 +1,70 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include "gsubgpos-graph.hh" + +namespace graph { + +gsubgpos_graph_context_t::gsubgpos_graph_context_t (hb_tag_t table_tag_, + graph_t& graph_) + : table_tag (table_tag_), + graph (graph_), + lookup_list_index (0), + lookups () +{ + if (table_tag_ != HB_OT_TAG_GPOS + && table_tag_ != HB_OT_TAG_GSUB) + return; + + GSTAR* gstar = graph::GSTAR::graph_to_gstar (graph_); + if (gstar) { + gstar->find_lookups (graph, lookups); + lookup_list_index = gstar->get_lookup_list_index (graph_); + } +} + +unsigned gsubgpos_graph_context_t::create_node (unsigned size) +{ + char* buffer = (char*) hb_calloc (1, size); + if (!buffer) + return -1; + + add_buffer (buffer); + + return graph.new_node (buffer, buffer + size); +} + +unsigned gsubgpos_graph_context_t::num_non_ext_subtables () { + unsigned count = 0; + for (auto l : lookups.values ()) + { + if (l->is_extension (table_tag)) continue; + count += l->number_of_subtables (); + } + return count; +} + +} diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh new file mode 100644 index 00000000000..9fe9662e645 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-context.hh @@ -0,0 +1,61 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include "graph.hh" +#include "../hb-ot-layout-gsubgpos.hh" + +#ifndef GRAPH_GSUBGPOS_CONTEXT_HH +#define GRAPH_GSUBGPOS_CONTEXT_HH + +namespace graph { + +struct Lookup; + +struct gsubgpos_graph_context_t +{ + hb_tag_t table_tag; + graph_t& graph; + unsigned lookup_list_index; + hb_hashmap_t lookups; + + + HB_INTERNAL gsubgpos_graph_context_t (hb_tag_t table_tag_, + graph_t& graph_); + + HB_INTERNAL unsigned create_node (unsigned size); + + void add_buffer (char* buffer) + { + graph.add_buffer (buffer); + } + + private: + HB_INTERNAL unsigned num_non_ext_subtables (); +}; + +} + +#endif // GRAPH_GSUBGPOS_CONTEXT diff --git a/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh new file mode 100644 index 00000000000..c170638409f --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/graph/gsubgpos-graph.hh @@ -0,0 +1,414 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#include "graph.hh" +#include "../hb-ot-layout-gsubgpos.hh" +#include "../OT/Layout/GSUB/ExtensionSubst.hh" +#include "gsubgpos-context.hh" +#include "pairpos-graph.hh" +#include "markbasepos-graph.hh" + +#ifndef GRAPH_GSUBGPOS_GRAPH_HH +#define GRAPH_GSUBGPOS_GRAPH_HH + +namespace graph { + +struct Lookup; + +template +struct ExtensionFormat1 : public OT::ExtensionFormat1 +{ + void reset(unsigned type) + { + this->format = 1; + this->extensionLookupType = type; + this->extensionOffset = 0; + } + + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + return vertex_len >= OT::ExtensionFormat1::static_size; + } + + unsigned get_lookup_type () const + { + return this->extensionLookupType; + } + + unsigned get_subtable_index (graph_t& graph, unsigned this_index) const + { + return graph.index_for_offset (this_index, &this->extensionOffset); + } +}; + +struct Lookup : public OT::Lookup +{ + unsigned number_of_subtables () const + { + return subTable.len; + } + + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < OT::Lookup::min_size) return false; + return vertex_len >= this->get_size (); + } + + bool is_extension (hb_tag_t table_tag) const + { + return lookupType == extension_type (table_tag); + } + + bool make_extension (gsubgpos_graph_context_t& c, + unsigned this_index) + { + unsigned type = lookupType; + unsigned ext_type = extension_type (c.table_tag); + if (!ext_type || is_extension (c.table_tag)) + { + // NOOP + return true; + } + + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Promoting lookup type %u (obj %u) to extension.", + type, + this_index); + + for (unsigned i = 0; i < subTable.len; i++) + { + unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]); + if (!make_subtable_extension (c, + this_index, + subtable_index)) + return false; + } + + lookupType = ext_type; + return true; + } + + bool split_subtables_if_needed (gsubgpos_graph_context_t& c, + unsigned this_index) + { + unsigned type = lookupType; + bool is_ext = is_extension (c.table_tag); + + if (c.table_tag != HB_OT_TAG_GPOS) + return true; + + if (!is_ext && + type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair && + type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase) + return true; + + hb_vector_t>> all_new_subtables; + for (unsigned i = 0; i < subTable.len; i++) + { + unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]); + unsigned parent_index = this_index; + if (is_ext) { + unsigned ext_subtable_index = subtable_index; + parent_index = ext_subtable_index; + ExtensionFormat1* extension = + (ExtensionFormat1*) + c.graph.object (ext_subtable_index).head; + if (!extension || !extension->sanitize (c.graph.vertices_[ext_subtable_index])) + continue; + + subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index); + type = extension->get_lookup_type (); + if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair + && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase) + continue; + } + + hb_vector_t new_sub_tables; + switch (type) + { + case 2: + new_sub_tables = split_subtable (c, parent_index, subtable_index); break; + case 4: + new_sub_tables = split_subtable (c, parent_index, subtable_index); break; + default: + break; + } + if (new_sub_tables.in_error ()) return false; + if (!new_sub_tables) continue; + hb_pair_t>* entry = all_new_subtables.push (); + entry->first = i; + entry->second = std::move (new_sub_tables); + } + + if (all_new_subtables) { + add_sub_tables (c, this_index, type, all_new_subtables); + } + + return true; + } + + template + hb_vector_t split_subtable (gsubgpos_graph_context_t& c, + unsigned parent_idx, + unsigned objidx) + { + T* sub_table = (T*) c.graph.object (objidx).head; + if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx])) + return hb_vector_t (); + + return sub_table->split_subtables (c, parent_idx, objidx); + } + + void add_sub_tables (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned type, + hb_vector_t>>& subtable_ids) + { + bool is_ext = is_extension (c.table_tag); + auto& v = c.graph.vertices_[this_index]; + fix_existing_subtable_links (c, this_index, subtable_ids); + + unsigned new_subtable_count = 0; + for (const auto& p : subtable_ids) + new_subtable_count += p.second.length; + + size_t new_size = v.table_size () + + new_subtable_count * OT::Offset16::static_size; + char* buffer = (char*) hb_calloc (1, new_size); + c.add_buffer (buffer); + hb_memcpy (buffer, v.obj.head, v.table_size()); + + v.obj.head = buffer; + v.obj.tail = buffer + new_size; + + Lookup* new_lookup = (Lookup*) buffer; + + unsigned shift = 0; + new_lookup->subTable.len = subTable.len + new_subtable_count; + for (const auto& p : subtable_ids) + { + unsigned offset_index = p.first + shift + 1; + shift += p.second.length; + + for (unsigned subtable_id : p.second) + { + if (is_ext) + { + unsigned ext_id = create_extension_subtable (c, subtable_id, type); + c.graph.vertices_[subtable_id].parents.push (ext_id); + subtable_id = ext_id; + } + + auto* link = v.obj.real_links.push (); + link->width = 2; + link->objidx = subtable_id; + link->position = (char*) &new_lookup->subTable[offset_index++] - + (char*) new_lookup; + c.graph.vertices_[subtable_id].parents.push (this_index); + } + } + + // Repacker sort order depends on link order, which we've messed up so resort it. + v.obj.real_links.qsort (); + + // The head location of the lookup has changed, invalidating the lookups map entry + // in the context. Update the map. + c.lookups.set (this_index, new_lookup); + } + + void fix_existing_subtable_links (gsubgpos_graph_context_t& c, + unsigned this_index, + hb_vector_t>>& subtable_ids) + { + auto& v = c.graph.vertices_[this_index]; + Lookup* lookup = (Lookup*) v.obj.head; + + unsigned shift = 0; + for (const auto& p : subtable_ids) + { + unsigned insert_index = p.first + shift; + unsigned pos_offset = p.second.length * OT::Offset16::static_size; + unsigned insert_offset = (char*) &lookup->subTable[insert_index] - (char*) lookup; + shift += p.second.length; + + for (auto& l : v.obj.all_links_writer ()) + { + if (l.position > insert_offset) l.position += pos_offset; + } + } + } + + unsigned create_extension_subtable (gsubgpos_graph_context_t& c, + unsigned subtable_index, + unsigned type) + { + unsigned extension_size = OT::ExtensionFormat1::static_size; + + unsigned ext_index = c.create_node (extension_size); + if (ext_index == (unsigned) -1) + return -1; + + auto& ext_vertex = c.graph.vertices_[ext_index]; + ExtensionFormat1* extension = + (ExtensionFormat1*) ext_vertex.obj.head; + extension->reset (type); + + // Make extension point at the subtable. + auto* l = ext_vertex.obj.real_links.push (); + + l->width = 4; + l->objidx = subtable_index; + l->position = 4; + + return ext_index; + } + + bool make_subtable_extension (gsubgpos_graph_context_t& c, + unsigned lookup_index, + unsigned subtable_index) + { + unsigned type = lookupType; + + unsigned ext_index = create_extension_subtable(c, subtable_index, type); + if (ext_index == (unsigned) -1) + return false; + + auto& lookup_vertex = c.graph.vertices_[lookup_index]; + for (auto& l : lookup_vertex.obj.real_links.writer ()) + { + if (l.objidx == subtable_index) + // Change lookup to point at the extension. + l.objidx = ext_index; + } + + // Make extension point at the subtable. + auto& ext_vertex = c.graph.vertices_[ext_index]; + auto& subtable_vertex = c.graph.vertices_[subtable_index]; + ext_vertex.parents.push (lookup_index); + subtable_vertex.remap_parent (lookup_index, ext_index); + + return true; + } + + private: + unsigned extension_type (hb_tag_t table_tag) const + { + switch (table_tag) + { + case HB_OT_TAG_GPOS: return 9; + case HB_OT_TAG_GSUB: return 7; + default: return 0; + } + } +}; + +template +struct LookupList : public OT::LookupList +{ + bool sanitize (const graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < OT::LookupList::min_size) return false; + return vertex_len >= OT::LookupList::item_size * this->len; + } +}; + +struct GSTAR : public OT::GSUBGPOS +{ + static GSTAR* graph_to_gstar (graph_t& graph) + { + const auto& r = graph.root (); + + GSTAR* gstar = (GSTAR*) r.obj.head; + if (!gstar || !gstar->sanitize (r)) + return nullptr; + + return gstar; + } + + const void* get_lookup_list_field_offset () const + { + switch (u.version.major) { + case 1: return u.version1.get_lookup_list_offset (); +#ifndef HB_NO_BEYOND_64K + case 2: return u.version2.get_lookup_list_offset (); +#endif + default: return 0; + } + } + + bool sanitize (const graph_t::vertex_t& vertex) + { + int64_t len = vertex.obj.tail - vertex.obj.head; + if (len < OT::GSUBGPOS::min_size) return false; + return len >= get_size (); + } + + void find_lookups (graph_t& graph, + hb_hashmap_t& lookups /* OUT */) + { + switch (u.version.major) { + case 1: find_lookups (graph, lookups); break; +#ifndef HB_NO_BEYOND_64K + case 2: find_lookups (graph, lookups); break; +#endif + } + } + + unsigned get_lookup_list_index (graph_t& graph) + { + return graph.index_for_offset (graph.root_idx (), + get_lookup_list_field_offset()); + } + + template + void find_lookups (graph_t& graph, + hb_hashmap_t& lookups /* OUT */) + { + unsigned lookup_list_idx = get_lookup_list_index (graph); + const LookupList* lookupList = + (const LookupList*) graph.object (lookup_list_idx).head; + if (!lookupList || !lookupList->sanitize (graph.vertices_[lookup_list_idx])) + return; + + for (unsigned i = 0; i < lookupList->len; i++) + { + unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i])); + Lookup* lookup = (Lookup*) graph.object (lookup_idx).head; + if (!lookup || !lookup->sanitize (graph.vertices_[lookup_idx])) continue; + lookups.set (lookup_idx, lookup); + } + } +}; + + + + +} + +#endif /* GRAPH_GSUBGPOS_GRAPH_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh new file mode 100644 index 00000000000..84ef5f71b93 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/graph/markbasepos-graph.hh @@ -0,0 +1,510 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#ifndef GRAPH_MARKBASEPOS_GRAPH_HH +#define GRAPH_MARKBASEPOS_GRAPH_HH + +#include "split-helpers.hh" +#include "coverage-graph.hh" +#include "../OT/Layout/GPOS/MarkBasePos.hh" +#include "../OT/Layout/GPOS/PosLookupSubTable.hh" + +namespace graph { + +struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix +{ + bool sanitize (graph_t::vertex_t& vertex, unsigned class_count) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < AnchorMatrix::min_size) return false; + + return vertex_len >= AnchorMatrix::min_size + + OT::Offset16::static_size * class_count * this->rows; + } + + bool shrink (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned old_class_count, + unsigned new_class_count) + { + if (new_class_count >= old_class_count) return false; + auto& o = c.graph.vertices_[this_index].obj; + unsigned base_count = rows; + o.tail = o.head + + AnchorMatrix::min_size + + OT::Offset16::static_size * base_count * new_class_count; + + // Reposition links into the new indexing scheme. + for (auto& link : o.real_links.writer ()) + { + unsigned index = (link.position - 2) / 2; + unsigned base = index / old_class_count; + unsigned klass = index % old_class_count; + if (klass >= new_class_count) + // should have already been removed + return false; + + unsigned new_index = base * new_class_count + klass; + + link.position = (char*) &(this->matrixZ[new_index]) - (char*) this; + } + + return true; + } + + unsigned clone (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned start, + unsigned end, + unsigned class_count) + { + unsigned base_count = rows; + unsigned new_class_count = end - start; + unsigned size = AnchorMatrix::min_size + + OT::Offset16::static_size * new_class_count * rows; + unsigned prime_id = c.create_node (size); + if (prime_id == (unsigned) -1) return -1; + AnchorMatrix* prime = (AnchorMatrix*) c.graph.object (prime_id).head; + prime->rows = base_count; + + auto& o = c.graph.vertices_[this_index].obj; + int num_links = o.real_links.length; + for (int i = 0; i < num_links; i++) + { + const auto& link = o.real_links[i]; + unsigned old_index = (link.position - 2) / OT::Offset16::static_size; + unsigned klass = old_index % class_count; + if (klass < start || klass >= end) continue; + + unsigned base = old_index / class_count; + unsigned new_klass = klass - start; + unsigned new_index = base * new_class_count + new_klass; + + + unsigned child_idx = link.objidx; + c.graph.add_link (&(prime->matrixZ[new_index]), + prime_id, + child_idx); + + auto& child = c.graph.vertices_[child_idx]; + child.remove_parent (this_index); + + o.real_links.remove_unordered (i); + num_links--; + i--; + } + + return prime_id; + } +}; + +struct MarkArray : public OT::Layout::GPOS_impl::MarkArray +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + unsigned min_size = MarkArray::min_size; + if (vertex_len < min_size) return false; + + return vertex_len >= get_size (); + } + + bool shrink (gsubgpos_graph_context_t& c, + const hb_hashmap_t& mark_array_links, + unsigned this_index, + unsigned new_class_count) + { + auto& o = c.graph.vertices_[this_index].obj; + for (const auto& link : o.real_links) + c.graph.vertices_[link.objidx].remove_parent (this_index); + o.real_links.reset (); + + unsigned new_index = 0; + for (const auto& record : this->iter ()) + { + unsigned klass = record.klass; + if (klass >= new_class_count) continue; + + (*this)[new_index].klass = klass; + unsigned position = (char*) &record.markAnchor - (char*) this; + unsigned* objidx; + if (!mark_array_links.has (position, &objidx)) + { + new_index++; + continue; + } + + c.graph.add_link (&(*this)[new_index].markAnchor, this_index, *objidx); + new_index++; + } + + this->len = new_index; + o.tail = o.head + MarkArray::min_size + + OT::Layout::GPOS_impl::MarkRecord::static_size * new_index; + return true; + } + + unsigned clone (gsubgpos_graph_context_t& c, + unsigned this_index, + const hb_hashmap_t& pos_to_index, + hb_set_t& marks, + unsigned start_class) + { + unsigned size = MarkArray::min_size + + OT::Layout::GPOS_impl::MarkRecord::static_size * + marks.get_population (); + unsigned prime_id = c.create_node (size); + if (prime_id == (unsigned) -1) return -1; + MarkArray* prime = (MarkArray*) c.graph.object (prime_id).head; + prime->len = marks.get_population (); + + + unsigned i = 0; + for (hb_codepoint_t mark : marks) + { + (*prime)[i].klass = (*this)[mark].klass - start_class; + unsigned offset_pos = (char*) &((*this)[mark].markAnchor) - (char*) this; + unsigned* anchor_index; + if (pos_to_index.has (offset_pos, &anchor_index)) + c.graph.move_child (this_index, + &((*this)[mark].markAnchor), + prime_id, + &((*prime)[i].markAnchor)); + + i++; + } + + return prime_id; + } +}; + +struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2 +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + return vertex_len >= MarkBasePosFormat1::static_size; + } + + hb_vector_t split_subtables (gsubgpos_graph_context_t& c, + unsigned parent_index, + unsigned this_index) + { + hb_set_t visited; + + const unsigned base_coverage_id = c.graph.index_for_offset (this_index, &baseCoverage); + const unsigned base_size = + OT::Layout::GPOS_impl::PairPosFormat1_3::min_size + + MarkArray::min_size + + AnchorMatrix::min_size + + c.graph.vertices_[base_coverage_id].table_size (); + + hb_vector_t class_to_info = get_class_info (c, this_index); + + unsigned class_count = classCount; + auto base_array = c.graph.as_table (this_index, + &baseArray, + class_count); + if (!base_array) return hb_vector_t (); + unsigned base_count = base_array.table->rows; + + unsigned partial_coverage_size = 4; + unsigned accumulated = base_size; + hb_vector_t split_points; + + for (unsigned klass = 0; klass < class_count; klass++) + { + class_info_t& info = class_to_info[klass]; + partial_coverage_size += OT::HBUINT16::static_size * info.marks.get_population (); + unsigned accumulated_delta = + OT::Layout::GPOS_impl::MarkRecord::static_size * info.marks.get_population () + + OT::Offset16::static_size * base_count; + + for (unsigned objidx : info.child_indices) + accumulated_delta += c.graph.find_subgraph_size (objidx, visited); + + accumulated += accumulated_delta; + unsigned total = accumulated + partial_coverage_size; + + if (total >= (1 << 16)) + { + split_points.push (klass); + accumulated = base_size + accumulated_delta; + partial_coverage_size = 4 + OT::HBUINT16::static_size * info.marks.get_population (); + visited.clear (); // node sharing isn't allowed between splits. + } + } + + + const unsigned mark_array_id = c.graph.index_for_offset (this_index, &markArray); + split_context_t split_context { + c, + this, + c.graph.duplicate_if_shared (parent_index, this_index), + std::move (class_to_info), + c.graph.vertices_[mark_array_id].position_to_index_map (), + }; + + return actuate_subtable_split (split_context, split_points); + } + + private: + + struct class_info_t { + hb_set_t marks; + hb_vector_t child_indices; + }; + + struct split_context_t { + gsubgpos_graph_context_t& c; + MarkBasePosFormat1* thiz; + unsigned this_index; + hb_vector_t class_to_info; + hb_hashmap_t mark_array_links; + + hb_set_t marks_for (unsigned start, unsigned end) + { + hb_set_t marks; + for (unsigned klass = start; klass < end; klass++) + { + + class_to_info[klass].marks.iter () + | hb_sink (marks) + ; + } + return marks; + } + + unsigned original_count () + { + return thiz->classCount; + } + + unsigned clone_range (unsigned start, unsigned end) + { + return thiz->clone_range (*this, this->this_index, start, end); + } + + bool shrink (unsigned count) + { + return thiz->shrink (*this, this->this_index, count); + } + }; + + hb_vector_t get_class_info (gsubgpos_graph_context_t& c, + unsigned this_index) + { + hb_vector_t class_to_info; + + unsigned class_count= classCount; + class_to_info.resize (class_count); + + auto mark_array = c.graph.as_table (this_index, &markArray); + if (!mark_array) return hb_vector_t (); + unsigned mark_count = mark_array.table->len; + for (unsigned mark = 0; mark < mark_count; mark++) + { + unsigned klass = (*mark_array.table)[mark].get_class (); + class_to_info[klass].marks.add (mark); + } + + for (const auto& link : mark_array.vertex->obj.real_links) + { + unsigned mark = (link.position - 2) / + OT::Layout::GPOS_impl::MarkRecord::static_size; + unsigned klass = (*mark_array.table)[mark].get_class (); + class_to_info[klass].child_indices.push (link.objidx); + } + + unsigned base_array_id = + c.graph.index_for_offset (this_index, &baseArray); + auto& base_array_v = c.graph.vertices_[base_array_id]; + + for (const auto& link : base_array_v.obj.real_links) + { + unsigned index = (link.position - 2) / OT::Offset16::static_size; + unsigned klass = index % class_count; + class_to_info[klass].child_indices.push (link.objidx); + } + + return class_to_info; + } + + bool shrink (split_context_t& sc, + unsigned this_index, + unsigned count) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " Shrinking MarkBasePosFormat1 (%u) to [0, %u).", + this_index, + count); + + unsigned old_count = classCount; + if (count >= old_count) + return true; + + classCount = count; + + auto mark_coverage = sc.c.graph.as_mutable_table (this_index, + &markCoverage); + if (!mark_coverage) return false; + hb_set_t marks = sc.marks_for (0, count); + auto new_coverage = + + hb_enumerate (mark_coverage.table->iter ()) + | hb_filter (marks, hb_first) + | hb_map_retains_sorting (hb_second) + ; + if (!Coverage::make_coverage (sc.c, + new_coverage, + mark_coverage.index, + 4 + 2 * marks.get_population ())) + return false; + + + auto base_array = sc.c.graph.as_mutable_table (this_index, + &baseArray, + old_count); + if (!base_array || !base_array.table->shrink (sc.c, + base_array.index, + old_count, + count)) + return false; + + auto mark_array = sc.c.graph.as_mutable_table (this_index, + &markArray); + if (!mark_array || !mark_array.table->shrink (sc.c, + sc.mark_array_links, + mark_array.index, + count)) + return false; + + return true; + } + + // Create a new MarkBasePos that has all of the data for classes from [start, end). + unsigned clone_range (split_context_t& sc, + unsigned this_index, + unsigned start, unsigned end) const + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " Cloning MarkBasePosFormat1 (%u) range [%u, %u).", this_index, start, end); + + graph_t& graph = sc.c.graph; + unsigned prime_size = OT::Layout::GPOS_impl::MarkBasePosFormat1_2::static_size; + + unsigned prime_id = sc.c.create_node (prime_size); + if (prime_id == (unsigned) -1) return -1; + + MarkBasePosFormat1* prime = (MarkBasePosFormat1*) graph.object (prime_id).head; + prime->format = this->format; + unsigned new_class_count = end - start; + prime->classCount = new_class_count; + + unsigned base_coverage_id = + graph.index_for_offset (sc.this_index, &baseCoverage); + graph.add_link (&(prime->baseCoverage), prime_id, base_coverage_id); + graph.duplicate (prime_id, base_coverage_id); + + auto mark_coverage = sc.c.graph.as_table (this_index, + &markCoverage); + if (!mark_coverage) return false; + hb_set_t marks = sc.marks_for (start, end); + auto new_coverage = + + hb_enumerate (mark_coverage.table->iter ()) + | hb_filter (marks, hb_first) + | hb_map_retains_sorting (hb_second) + ; + if (!Coverage::add_coverage (sc.c, + prime_id, + 2, + + new_coverage, + marks.get_population () * 2 + 4)) + return -1; + + auto mark_array = + graph.as_table (sc.this_index, &markArray); + if (!mark_array) return -1; + unsigned new_mark_array = + mark_array.table->clone (sc.c, + mark_array.index, + sc.mark_array_links, + marks, + start); + graph.add_link (&(prime->markArray), prime_id, new_mark_array); + + unsigned class_count = classCount; + auto base_array = + graph.as_table (sc.this_index, &baseArray, class_count); + if (!base_array) return -1; + unsigned new_base_array = + base_array.table->clone (sc.c, + base_array.index, + start, end, this->classCount); + graph.add_link (&(prime->baseArray), prime_id, new_base_array); + + return prime_id; + } +}; + + +struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos +{ + hb_vector_t split_subtables (gsubgpos_graph_context_t& c, + unsigned parent_index, + unsigned this_index) + { + switch (u.format) { + case 1: + return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index); +#ifndef HB_NO_BEYOND_64K + case 2: HB_FALLTHROUGH; + // Don't split 24bit PairPos's. +#endif + default: + return hb_vector_t (); + } + } + + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < u.format.get_size ()) return false; + + switch (u.format) { + case 1: + return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex); +#ifndef HB_NO_BEYOND_64K + case 2: HB_FALLTHROUGH; +#endif + default: + // We don't handle format 3 and 4 here. + return false; + } + } +}; + + +} + +#endif // GRAPH_MARKBASEPOS_GRAPH_HH diff --git a/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh new file mode 100644 index 00000000000..1c13eb24f94 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/graph/pairpos-graph.hh @@ -0,0 +1,647 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#ifndef GRAPH_PAIRPOS_GRAPH_HH +#define GRAPH_PAIRPOS_GRAPH_HH + +#include "split-helpers.hh" +#include "coverage-graph.hh" +#include "classdef-graph.hh" +#include "../OT/Layout/GPOS/PairPos.hh" +#include "../OT/Layout/GPOS/PosLookupSubTable.hh" + +namespace graph { + +struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3 +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3::min_size; + if (vertex_len < min_size) return false; + + return vertex_len >= + min_size + pairSet.get_size () - pairSet.len.get_size(); + } + + hb_vector_t split_subtables (gsubgpos_graph_context_t& c, + unsigned parent_index, + unsigned this_index) + { + hb_set_t visited; + + const unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); + const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size (); + const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3::min_size; + + unsigned partial_coverage_size = 4; + unsigned accumulated = base_size; + hb_vector_t split_points; + for (unsigned i = 0; i < pairSet.len; i++) + { + unsigned pair_set_index = pair_set_graph_index (c, this_index, i); + unsigned accumulated_delta = + c.graph.find_subgraph_size (pair_set_index, visited) + + SmallTypes::size; // for PairSet offset. + partial_coverage_size += OT::HBUINT16::static_size; + + accumulated += accumulated_delta; + unsigned total = accumulated + hb_min (partial_coverage_size, coverage_size); + + if (total >= (1 << 16)) + { + split_points.push (i); + accumulated = base_size + accumulated_delta; + partial_coverage_size = 6; + visited.clear (); // node sharing isn't allowed between splits. + } + } + + split_context_t split_context { + c, + this, + c.graph.duplicate_if_shared (parent_index, this_index), + }; + + return actuate_subtable_split (split_context, split_points); + } + + private: + + struct split_context_t { + gsubgpos_graph_context_t& c; + PairPosFormat1* thiz; + unsigned this_index; + + unsigned original_count () + { + return thiz->pairSet.len; + } + + unsigned clone_range (unsigned start, unsigned end) + { + return thiz->clone_range (this->c, this->this_index, start, end); + } + + bool shrink (unsigned count) + { + return thiz->shrink (this->c, this->this_index, count); + } + }; + + bool shrink (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned count) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " Shrinking PairPosFormat1 (%u) to [0, %u).", + this_index, + count); + unsigned old_count = pairSet.len; + if (count >= old_count) + return true; + + pairSet.len = count; + c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size; + + auto coverage = c.graph.as_mutable_table (this_index, &this->coverage); + if (!coverage) return false; + + unsigned coverage_size = coverage.vertex->table_size (); + auto new_coverage = + + hb_zip (coverage.table->iter (), hb_range ()) + | hb_filter ([&] (hb_pair_t p) { + return p.second < count; + }) + | hb_map_retains_sorting (hb_first) + ; + + return Coverage::make_coverage (c, new_coverage, coverage.index, coverage_size); + } + + // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive). + // Returns object id of the new object. + unsigned clone_range (gsubgpos_graph_context_t& c, + unsigned this_index, + unsigned start, unsigned end) const + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " Cloning PairPosFormat1 (%u) range [%u, %u).", this_index, start, end); + + unsigned num_pair_sets = end - start; + unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat1_3::min_size + + num_pair_sets * SmallTypes::size; + + unsigned pair_pos_prime_id = c.create_node (prime_size); + if (pair_pos_prime_id == (unsigned) -1) return -1; + + PairPosFormat1* pair_pos_prime = (PairPosFormat1*) c.graph.object (pair_pos_prime_id).head; + pair_pos_prime->format = this->format; + pair_pos_prime->valueFormat[0] = this->valueFormat[0]; + pair_pos_prime->valueFormat[1] = this->valueFormat[1]; + pair_pos_prime->pairSet.len = num_pair_sets; + + for (unsigned i = start; i < end; i++) + { + c.graph.move_child<> (this_index, + &pairSet[i], + pair_pos_prime_id, + &pair_pos_prime->pairSet[i - start]); + } + + unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); + if (!Coverage::clone_coverage (c, + coverage_id, + pair_pos_prime_id, + 2, + start, end)) + return -1; + + return pair_pos_prime_id; + } + + + + unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const + { + return c.graph.index_for_offset (this_index, &pairSet[i]); + } +}; + +struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4 +{ + bool sanitize (graph_t::vertex_t& vertex) const + { + size_t vertex_len = vertex.table_size (); + unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4::min_size; + if (vertex_len < min_size) return false; + + const unsigned class1_count = class1Count; + return vertex_len >= + min_size + class1_count * get_class1_record_size (); + } + + hb_vector_t split_subtables (gsubgpos_graph_context_t& c, + unsigned parent_index, + unsigned this_index) + { + const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4::min_size; + const unsigned class_def_2_size = size_of (c, this_index, &classDef2); + const Coverage* coverage = get_coverage (c, this_index); + const ClassDef* class_def_1 = get_class_def_1 (c, this_index); + auto gid_and_class = + + coverage->iter () + | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { + return hb_pair_t (gid, class_def_1->get_class (gid)); + }) + ; + class_def_size_estimator_t estimator (gid_and_class); + + const unsigned class1_count = class1Count; + const unsigned class2_count = class2Count; + const unsigned class1_record_size = get_class1_record_size (); + + const unsigned value_1_len = valueFormat1.get_len (); + const unsigned value_2_len = valueFormat2.get_len (); + const unsigned total_value_len = value_1_len + value_2_len; + + unsigned accumulated = base_size; + unsigned coverage_size = 4; + unsigned class_def_1_size = 4; + unsigned max_coverage_size = coverage_size; + unsigned max_class_def_1_size = class_def_1_size; + + hb_vector_t split_points; + + hb_hashmap_t device_tables = get_all_device_tables (c, this_index); + hb_vector_t format1_device_table_indices = valueFormat1.get_device_table_indices (); + hb_vector_t format2_device_table_indices = valueFormat2.get_device_table_indices (); + bool has_device_tables = bool(format1_device_table_indices) || bool(format2_device_table_indices); + + hb_set_t visited; + for (unsigned i = 0; i < class1_count; i++) + { + unsigned accumulated_delta = class1_record_size; + coverage_size += estimator.incremental_coverage_size (i); + class_def_1_size += estimator.incremental_class_def_size (i); + max_coverage_size = hb_max (max_coverage_size, coverage_size); + max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size); + + if (has_device_tables) { + for (unsigned j = 0; j < class2_count; j++) + { + unsigned value1_index = total_value_len * (class2_count * i + j); + unsigned value2_index = value1_index + value_1_len; + accumulated_delta += size_of_value_record_children (c, + device_tables, + format1_device_table_indices, + value1_index, + visited); + accumulated_delta += size_of_value_record_children (c, + device_tables, + format2_device_table_indices, + value2_index, + visited); + } + } + + accumulated += accumulated_delta; + unsigned total = accumulated + + coverage_size + class_def_1_size + class_def_2_size + // The largest object will pack last and can exceed the size limit. + - hb_max (hb_max (coverage_size, class_def_1_size), class_def_2_size); + if (total >= (1 << 16)) + { + split_points.push (i); + // split does not include i, so add the size for i when we reset the size counters. + accumulated = base_size + accumulated_delta; + coverage_size = 4 + estimator.incremental_coverage_size (i); + class_def_1_size = 4 + estimator.incremental_class_def_size (i); + visited.clear (); // node sharing isn't allowed between splits. + } + } + + split_context_t split_context { + c, + this, + c.graph.duplicate_if_shared (parent_index, this_index), + class1_record_size, + total_value_len, + value_1_len, + value_2_len, + max_coverage_size, + max_class_def_1_size, + device_tables, + format1_device_table_indices, + format2_device_table_indices + }; + + return actuate_subtable_split (split_context, split_points); + } + private: + + struct split_context_t + { + gsubgpos_graph_context_t& c; + PairPosFormat2* thiz; + unsigned this_index; + unsigned class1_record_size; + unsigned value_record_len; + unsigned value1_record_len; + unsigned value2_record_len; + unsigned max_coverage_size; + unsigned max_class_def_size; + + const hb_hashmap_t& device_tables; + const hb_vector_t& format1_device_table_indices; + const hb_vector_t& format2_device_table_indices; + + unsigned original_count () + { + return thiz->class1Count; + } + + unsigned clone_range (unsigned start, unsigned end) + { + return thiz->clone_range (*this, start, end); + } + + bool shrink (unsigned count) + { + return thiz->shrink (*this, count); + } + }; + + size_t get_class1_record_size () const + { + const size_t class2_count = class2Count; + return + class2_count * (valueFormat1.get_size () + valueFormat2.get_size ()); + } + + unsigned clone_range (split_context_t& split_context, + unsigned start, unsigned end) const + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " Cloning PairPosFormat2 (%u) range [%u, %u).", split_context.this_index, start, end); + + graph_t& graph = split_context.c.graph; + + unsigned num_records = end - start; + unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat2_4::min_size + + num_records * split_context.class1_record_size; + + unsigned pair_pos_prime_id = split_context.c.create_node (prime_size); + if (pair_pos_prime_id == (unsigned) -1) return -1; + + PairPosFormat2* pair_pos_prime = + (PairPosFormat2*) graph.object (pair_pos_prime_id).head; + pair_pos_prime->format = this->format; + pair_pos_prime->valueFormat1 = this->valueFormat1; + pair_pos_prime->valueFormat2 = this->valueFormat2; + pair_pos_prime->class1Count = num_records; + pair_pos_prime->class2Count = this->class2Count; + clone_class1_records (split_context, + pair_pos_prime_id, + start, + end); + + unsigned coverage_id = + graph.index_for_offset (split_context.this_index, &coverage); + unsigned class_def_1_id = + graph.index_for_offset (split_context.this_index, &classDef1); + auto& coverage_v = graph.vertices_[coverage_id]; + auto& class_def_1_v = graph.vertices_[class_def_1_id]; + Coverage* coverage_table = (Coverage*) coverage_v.obj.head; + ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head; + if (!coverage_table + || !coverage_table->sanitize (coverage_v) + || !class_def_1_table + || !class_def_1_table->sanitize (class_def_1_v)) + return -1; + + auto klass_map = + + coverage_table->iter () + | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { + return hb_pair_t (gid, class_def_1_table->get_class (gid)); + }) + | hb_filter ([&] (hb_codepoint_t klass) { + return klass >= start && klass < end; + }, hb_second) + | hb_map_retains_sorting ([&] (hb_pair_t gid_and_class) { + // Classes must be from 0...N so subtract start + return hb_pair_t (gid_and_class.first, gid_and_class.second - start); + }) + ; + + if (!Coverage::add_coverage (split_context.c, + pair_pos_prime_id, + 2, + + klass_map | hb_map_retains_sorting (hb_first), + split_context.max_coverage_size)) + return -1; + + // classDef1 + if (!ClassDef::add_class_def (split_context.c, + pair_pos_prime_id, + 8, + + klass_map, + split_context.max_class_def_size)) + return -1; + + // classDef2 + unsigned class_def_2_id = + graph.index_for_offset (split_context.this_index, &classDef2); + auto* class_def_link = graph.vertices_[pair_pos_prime_id].obj.real_links.push (); + class_def_link->width = SmallTypes::size; + class_def_link->objidx = class_def_2_id; + class_def_link->position = 10; + graph.vertices_[class_def_2_id].parents.push (pair_pos_prime_id); + graph.duplicate (pair_pos_prime_id, class_def_2_id); + + return pair_pos_prime_id; + } + + void clone_class1_records (split_context_t& split_context, + unsigned pair_pos_prime_id, + unsigned start, unsigned end) const + { + PairPosFormat2* pair_pos_prime = + (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head; + + char* start_addr = ((char*)&values[0]) + start * split_context.class1_record_size; + unsigned num_records = end - start; + hb_memcpy (&pair_pos_prime->values[0], + start_addr, + num_records * split_context.class1_record_size); + + if (!split_context.format1_device_table_indices + && !split_context.format2_device_table_indices) + // No device tables to move over. + return; + + unsigned class2_count = class2Count; + for (unsigned i = start; i < end; i++) + { + for (unsigned j = 0; j < class2_count; j++) + { + unsigned value1_index = split_context.value_record_len * (class2_count * i + j); + unsigned value2_index = value1_index + split_context.value1_record_len; + + unsigned new_value1_index = split_context.value_record_len * (class2_count * (i - start) + j); + unsigned new_value2_index = new_value1_index + split_context.value1_record_len; + + transfer_device_tables (split_context, + pair_pos_prime_id, + split_context.format1_device_table_indices, + value1_index, + new_value1_index); + + transfer_device_tables (split_context, + pair_pos_prime_id, + split_context.format2_device_table_indices, + value2_index, + new_value2_index); + } + } + } + + void transfer_device_tables (split_context_t& split_context, + unsigned pair_pos_prime_id, + const hb_vector_t& device_table_indices, + unsigned old_value_record_index, + unsigned new_value_record_index) const + { + PairPosFormat2* pair_pos_prime = + (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head; + + for (unsigned i : device_table_indices) + { + OT::Offset16* record = (OT::Offset16*) &values[old_value_record_index + i]; + unsigned record_position = ((char*) record) - ((char*) this); + if (!split_context.device_tables.has (record_position)) continue; + + split_context.c.graph.move_child ( + split_context.this_index, + record, + pair_pos_prime_id, + (OT::Offset16*) &pair_pos_prime->values[new_value_record_index + i]); + } + } + + bool shrink (split_context_t& split_context, + unsigned count) + { + DEBUG_MSG (SUBSET_REPACK, nullptr, + " Shrinking PairPosFormat2 (%u) to [0, %u).", + split_context.this_index, + count); + unsigned old_count = class1Count; + if (count >= old_count) + return true; + + graph_t& graph = split_context.c.graph; + class1Count = count; + graph.vertices_[split_context.this_index].obj.tail -= + (old_count - count) * split_context.class1_record_size; + + auto coverage = + graph.as_mutable_table (split_context.this_index, &this->coverage); + if (!coverage) return false; + + auto class_def_1 = + graph.as_mutable_table (split_context.this_index, &classDef1); + if (!class_def_1) return false; + + auto klass_map = + + coverage.table->iter () + | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { + return hb_pair_t (gid, class_def_1.table->get_class (gid)); + }) + | hb_filter ([&] (hb_codepoint_t klass) { + return klass < count; + }, hb_second) + ; + + auto new_coverage = + klass_map | hb_map_retains_sorting (hb_first); + if (!Coverage::make_coverage (split_context.c, + + new_coverage, + coverage.index, + // existing ranges my not be kept, worst case size is a format 1 + // coverage table. + 4 + new_coverage.len() * 2)) + return false; + + return ClassDef::make_class_def (split_context.c, + + klass_map, + class_def_1.index, + class_def_1.vertex->table_size ()); + } + + hb_hashmap_t + get_all_device_tables (gsubgpos_graph_context_t& c, + unsigned this_index) const + { + const auto& v = c.graph.vertices_[this_index]; + return v.position_to_index_map (); + } + + const Coverage* get_coverage (gsubgpos_graph_context_t& c, + unsigned this_index) const + { + unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); + auto& coverage_v = c.graph.vertices_[coverage_id]; + + Coverage* coverage_table = (Coverage*) coverage_v.obj.head; + if (!coverage_table || !coverage_table->sanitize (coverage_v)) + return &Null(Coverage); + return coverage_table; + } + + const ClassDef* get_class_def_1 (gsubgpos_graph_context_t& c, + unsigned this_index) const + { + unsigned class_def_1_id = c.graph.index_for_offset (this_index, &classDef1); + auto& class_def_1_v = c.graph.vertices_[class_def_1_id]; + + ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head; + if (!class_def_1_table || !class_def_1_table->sanitize (class_def_1_v)) + return &Null(ClassDef); + return class_def_1_table; + } + + unsigned size_of_value_record_children (gsubgpos_graph_context_t& c, + const hb_hashmap_t& device_tables, + const hb_vector_t device_table_indices, + unsigned value_record_index, + hb_set_t& visited) + { + unsigned size = 0; + for (unsigned i : device_table_indices) + { + OT::Layout::GPOS_impl::Value* record = &values[value_record_index + i]; + unsigned record_position = ((char*) record) - ((char*) this); + unsigned* obj_idx; + if (!device_tables.has (record_position, &obj_idx)) continue; + size += c.graph.find_subgraph_size (*obj_idx, visited); + } + return size; + } + + unsigned size_of (gsubgpos_graph_context_t& c, + unsigned this_index, + const void* offset) const + { + const unsigned id = c.graph.index_for_offset (this_index, offset); + return c.graph.vertices_[id].table_size (); + } +}; + +struct PairPos : public OT::Layout::GPOS_impl::PairPos +{ + hb_vector_t split_subtables (gsubgpos_graph_context_t& c, + unsigned parent_index, + unsigned this_index) + { + switch (u.format) { + case 1: + return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index); + case 2: + return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index); +#ifndef HB_NO_BEYOND_64K + case 3: HB_FALLTHROUGH; + case 4: HB_FALLTHROUGH; + // Don't split 24bit PairPos's. +#endif + default: + return hb_vector_t (); + } + } + + bool sanitize (graph_t::vertex_t& vertex) const + { + int64_t vertex_len = vertex.obj.tail - vertex.obj.head; + if (vertex_len < u.format.get_size ()) return false; + + switch (u.format) { + case 1: + return ((PairPosFormat1*)(&u.format1))->sanitize (vertex); + case 2: + return ((PairPosFormat2*)(&u.format2))->sanitize (vertex); +#ifndef HB_NO_BEYOND_64K + case 3: HB_FALLTHROUGH; + case 4: HB_FALLTHROUGH; +#endif + default: + // We don't handle format 3 and 4 here. + return false; + } + } +}; + +} + +#endif // GRAPH_PAIRPOS_GRAPH_HH diff --git a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh index ecc6cc5aea2..040fd1de5fd 100644 --- a/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh +++ b/src/java.desktop/share/native/libharfbuzz/graph/serialize.hh @@ -33,6 +33,23 @@ struct overflow_record_t { unsigned parent; unsigned child; + + bool operator != (const overflow_record_t o) const + { return !(*this == o); } + + inline bool operator == (const overflow_record_t& o) const + { + return parent == o.parent && + child == o.child; + } + + inline uint32_t hash () const + { + uint32_t current = 0; + current = current * 31 + hb_hash (parent); + current = current * 31 + hb_hash (child); + return current; + } }; inline @@ -94,6 +111,7 @@ will_overflow (graph_t& graph, if (overflows) overflows->resize (0); graph.update_positions (); + hb_hashmap_t record_set; const auto& vertices = graph.vertices_; for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--) { @@ -109,7 +127,10 @@ will_overflow (graph_t& graph, overflow_record_t r; r.parent = parent_idx; r.child = link.objidx; + if (record_set.has(&r)) continue; // don't keep duplicate overflows. + overflows->push (r); + record_set.set(&r, true); } } @@ -132,8 +153,8 @@ void print_overflows (graph_t& graph, const auto& child = graph.vertices_[o.child]; DEBUG_MSG (SUBSET_REPACK, nullptr, " overflow from " - "%4d (%4d in, %4d out, space %2d) => " - "%4d (%4d in, %4d out, space %2d)", + "%4u (%4u in, %4u out, space %2u) => " + "%4u (%4u in, %4u out, space %2u)", o.parent, parent.incoming_edges (), parent.obj.real_links.length + parent.obj.virtual_links.length, @@ -144,7 +165,7 @@ void print_overflows (graph_t& graph, graph.space_for (o.child)); } if (overflows.length > 10) { - DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10); + DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %u more overflows.", overflows.length - 10); } } @@ -223,7 +244,7 @@ inline hb_blob_t* serialize (const graph_t& graph) return nullptr; } - memcpy (start, vertices[i].obj.head, size); + hb_memcpy (start, vertices[i].obj.head, size); // Only real links needs to be serialized. for (const auto& link : vertices[i].obj.real_links) diff --git a/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh b/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh new file mode 100644 index 00000000000..61fd7c2d2ff --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/graph/split-helpers.hh @@ -0,0 +1,69 @@ +/* + * Copyright © 2022 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Garret Rieger + */ + +#ifndef GRAPH_SPLIT_HELPERS_HH +#define GRAPH_SPLIT_HELPERS_HH + +namespace graph { + +template +HB_INTERNAL +hb_vector_t actuate_subtable_split (Context& split_context, + const hb_vector_t& split_points) +{ + hb_vector_t new_objects; + if (!split_points) + return new_objects; + + for (unsigned i = 0; i < split_points.length; i++) + { + unsigned start = split_points[i]; + unsigned end = (i < split_points.length - 1) + ? split_points[i + 1] + : split_context.original_count (); + unsigned id = split_context.clone_range (start, end); + + if (id == (unsigned) -1) + { + new_objects.reset (); + new_objects.allocated = -1; // mark error + return new_objects; + } + new_objects.push (id); + } + + if (!split_context.shrink (split_points[0])) + { + new_objects.reset (); + new_objects.allocated = -1; // mark error + } + + return new_objects; +} + +} + +#endif // GRAPH_SPLIT_HELPERS_HH diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh index ed376b9efc7..24d53e224c7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-bsln-table.hh @@ -42,7 +42,7 @@ struct BaselineTableFormat0Part bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: @@ -78,7 +78,7 @@ struct BaselineTableFormat2Part bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh index b8c9b992fb8..3d633845a0f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-common.hh @@ -28,6 +28,7 @@ #define HB_AAT_LAYOUT_COMMON_HH #include "hb-aat-layout.hh" +#include "hb-aat-map.hh" #include "hb-open-type.hh" namespace OT { @@ -39,6 +40,43 @@ namespace AAT { using namespace OT; +struct ankr; + +struct hb_aat_apply_context_t : + hb_dispatch_context_t +{ + const char *get_name () { return "APPLY"; } + template + return_t dispatch (const T &obj) { return obj.apply (this); } + static return_t default_return_value () { return false; } + bool stop_sublookup_iteration (return_t r) const { return r; } + + const hb_ot_shape_plan_t *plan; + hb_font_t *font; + hb_face_t *face; + hb_buffer_t *buffer; + hb_sanitize_context_t sanitizer; + const ankr *ankr_table; + const OT::GDEF *gdef_table; + const hb_sorted_vector_t *range_flags = nullptr; + hb_mask_t subtable_flags = 0; + + /* Unused. For debug tracing only. */ + unsigned int lookup_index; + + HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, + hb_font_t *font_, + hb_buffer_t *buffer_, + hb_blob_t *blob = const_cast (&Null (hb_blob_t))); + + HB_INTERNAL ~hb_aat_apply_context_t (); + + HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_); + + void set_lookup_index (unsigned int i) { lookup_index = i; } +}; + + /* * Lookup Table */ @@ -415,18 +453,7 @@ struct Lookup public: DEFINE_SIZE_UNION (2, format); }; -/* Lookup 0 has unbounded size (dependant on num_glyphs). So we need to defined - * special NULL objects for Lookup<> objects, but since it's template our macros - * don't work. So we have to hand-code them here. UGLY. */ -} /* Close namespace. */ -/* Ugly hand-coded null objects for template Lookup<> :(. */ -extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2]; -template -struct Null> { - static AAT::Lookup const & get_null () - { return *reinterpret_cast *> (_hb_Null_AAT_Lookup); } -}; -namespace AAT { +DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2); enum { DELETED_GLYPH = 0xFFFF }; @@ -681,6 +708,13 @@ struct ObsoleteTypes const void *base, const T *array) { + /* https://github.com/harfbuzz/harfbuzz/issues/3483 */ + /* If offset is less than base, return an offset that would + * result in an address half a 32bit address-space away, + * to make sure sanitize fails even on 32bit builds. */ + if (unlikely (offset < unsigned ((const char *) array - (const char *) base))) + return INT_MAX / T::static_size; + /* https://github.com/harfbuzz/harfbuzz/issues/2816 */ return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size; } @@ -744,16 +778,44 @@ struct StateTableDriver num_glyphs (face_->get_num_glyphs ()) {} template - void drive (context_t *c) + void drive (context_t *c, hb_aat_apply_context_t *ac) { if (!c->in_place) buffer->clear_output (); int state = StateTableT::STATE_START_OF_TEXT; + // If there's only one range, we already checked the flag. + auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr; for (buffer->idx = 0; buffer->successful;) { + /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */ + if (last_range) + { + auto *range = last_range; + if (buffer->idx < buffer->len) + { + unsigned cluster = buffer->cur().cluster; + while (cluster < range->cluster_first) + range--; + while (cluster > range->cluster_last) + range++; + + + last_range = range; + } + if (!(range->flags & ac->subtable_flags)) + { + if (buffer->idx == buffer->len || unlikely (!buffer->successful)) + break; + + state = StateTableT::STATE_START_OF_TEXT; + (void) buffer->next_glyph (); + continue; + } + } + unsigned int klass = buffer->idx < buffer->len ? - machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) : + machine.get_class (buffer->cur().codepoint, num_glyphs) : (unsigned) StateTableT::CLASS_END_OF_TEXT; DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); const EntryT &entry = machine.get_entry (state, klass); @@ -849,41 +911,6 @@ struct StateTableDriver }; -struct ankr; - -struct hb_aat_apply_context_t : - hb_dispatch_context_t -{ - const char *get_name () { return "APPLY"; } - template - return_t dispatch (const T &obj) { return obj.apply (this); } - static return_t default_return_value () { return false; } - bool stop_sublookup_iteration (return_t r) const { return r; } - - const hb_ot_shape_plan_t *plan; - hb_font_t *font; - hb_face_t *face; - hb_buffer_t *buffer; - hb_sanitize_context_t sanitizer; - const ankr *ankr_table; - const OT::GDEF *gdef_table; - - /* Unused. For debug tracing only. */ - unsigned int lookup_index; - - HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, - hb_font_t *font_, - hb_buffer_t *buffer_, - hb_blob_t *blob = const_cast (&Null (hb_blob_t))); - - HB_INTERNAL ~hb_aat_apply_context_t (); - - HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_); - - void set_lookup_index (unsigned int i) { lookup_index = i; } -}; - - } /* namespace AAT */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh index 527bfe45b35..04260a94616 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-feat-table.hh @@ -62,7 +62,7 @@ struct SettingName bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh index 4b1319ac31c..0588310b53b 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-just-table.hh @@ -48,7 +48,7 @@ struct ActionSubrecordHeader bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } HBUINT16 actionClass; /* The JustClass value associated with this @@ -65,14 +65,14 @@ struct DecompositionAction bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } ActionSubrecordHeader header; - HBFixed lowerLimit; /* If the distance factor is less than this value, + F16DOT16 lowerLimit; /* If the distance factor is less than this value, * then the ligature is decomposed. */ - HBFixed upperLimit; /* If the distance factor is greater than this value, + F16DOT16 upperLimit; /* If the distance factor is greater than this value, * then the ligature is decomposed. */ HBUINT16 order; /* Numerical order in which this ligature will * be decomposed; you may want infrequent ligatures @@ -112,13 +112,13 @@ struct ConditionalAddGlyphAction bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: ActionSubrecordHeader header; - HBFixed substThreshold; /* Distance growth factor (in ems) at which + F16DOT16 substThreshold; /* Distance growth factor (in ems) at which * this glyph is replaced and the growth factor * recalculated. */ HBGlyphID16 addGlyph; /* Glyph to be added as kashida. If this value is @@ -137,7 +137,7 @@ struct DuctileGlyphAction bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: @@ -146,13 +146,13 @@ struct DuctileGlyphAction HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis. * This would normally be 0x64756374 ('duct'), * but you may use any axis the font contains. */ - HBFixed minimumLimit; /* The lowest value for the ductility axis that + F16DOT16 minimumLimit; /* The lowest value for the ductility axis that * still yields an acceptable appearance. Normally * this will be 1.0. */ - HBFixed noStretchValue; /* This is the default value that corresponds to + F16DOT16 noStretchValue; /* This is the default value that corresponds to * no change in appearance. Normally, this will * be 1.0. */ - HBFixed maximumLimit; /* The highest value for the ductility axis that + F16DOT16 maximumLimit; /* The highest value for the ductility axis that * still yields an acceptable appearance. */ public: DEFINE_SIZE_STATIC (22); @@ -163,7 +163,7 @@ struct RepeatedAddGlyphAction bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: @@ -271,14 +271,14 @@ struct JustWidthDeltaEntry }; protected: - HBFixed beforeGrowLimit;/* The ratio by which the advance width of the + F16DOT16 beforeGrowLimit;/* The ratio by which the advance width of the * glyph is permitted to grow on the left or top side. */ - HBFixed beforeShrinkLimit; + F16DOT16 beforeShrinkLimit; /* The ratio by which the advance width of the * glyph is permitted to shrink on the left or top side. */ - HBFixed afterGrowLimit; /* The ratio by which the advance width of the glyph + F16DOT16 afterGrowLimit; /* The ratio by which the advance width of the glyph * is permitted to shrink on the left or top side. */ - HBFixed afterShrinkLimit; + F16DOT16 afterShrinkLimit; /* The ratio by which the advance width of the glyph * is at most permitted to shrink on the right or * bottom side. */ @@ -294,7 +294,7 @@ struct WidthDeltaPair bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh index 51cb106bb08..2bc7b03ce89 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-kerx-table.hh @@ -350,7 +350,7 @@ struct KerxSubTableFormat1 driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->font->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (true); } @@ -594,7 +594,7 @@ struct KerxSubTableFormat4 driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->font->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (true); } @@ -751,7 +751,7 @@ struct KerxSubTableHeader bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } public: @@ -869,6 +869,8 @@ struct KerxTable bool apply (AAT::hb_aat_apply_context_t *c) const { + c->buffer->unsafe_to_concat (); + typedef typename T::SubTable SubTable; bool ret = false; @@ -889,7 +891,7 @@ struct KerxTable reverse = bool (st->u.header.coverage & st->u.header.Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); - if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index)) + if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index)) goto skip; if (!seenCrossStream && @@ -921,7 +923,7 @@ struct KerxTable if (reverse) c->buffer->reverse (); - (void) c->buffer->message (c->font, "end subtable %d", c->lookup_index); + (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index); skip: st = &StructAfter (*st); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh index 889784e7d52..81e126d5eb1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-morx-table.hh @@ -131,14 +131,14 @@ struct RearrangementSubtable hb_glyph_info_t *info = buffer->info; hb_glyph_info_t buf[4]; - memcpy (buf, info + start, l * sizeof (buf[0])); - memcpy (buf + 2, info + end - r, r * sizeof (buf[0])); + hb_memcpy (buf, info + start, l * sizeof (buf[0])); + hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0])); if (l != r) memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0])); - memcpy (info + start, buf + 2, r * sizeof (buf[0])); - memcpy (info + end - l, buf, l * sizeof (buf[0])); + hb_memcpy (info + start, buf + 2, r * sizeof (buf[0])); + hb_memcpy (info + end - l, buf, l * sizeof (buf[0])); if (reverse_l) { buf[0] = info[end - 1]; @@ -169,7 +169,7 @@ struct RearrangementSubtable driver_context_t dc (this); StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (dc.ret); } @@ -325,7 +325,7 @@ struct ContextualSubtable driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (dc.ret); } @@ -525,7 +525,7 @@ struct LigatureSubtable if (unlikely (!componentData.sanitize (&c->sanitizer))) break; ligature_idx += componentData; - DEBUG_MSG (APPLY, nullptr, "Action store %u last %u", + DEBUG_MSG (APPLY, nullptr, "Action store %d last %d", bool (action & LigActionStore), bool (action & LigActionLast)); if (action & (LigActionStore | LigActionLast)) @@ -577,7 +577,7 @@ struct LigatureSubtable driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (dc.ret); } @@ -618,8 +618,27 @@ struct NoncontextualSubtable hb_glyph_info_t *info = c->buffer->info; unsigned int count = c->buffer->len; + // If there's only one range, we already checked the flag. + auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr; for (unsigned int i = 0; i < count; i++) { + /* This block copied from StateTableDriver::drive. Keep in sync. */ + if (last_range) + { + auto *range = last_range; + { + unsigned cluster = info[i].cluster; + while (cluster < range->cluster_first) + range--; + while (cluster > range->cluster_last) + range++; + + last_range = range; + } + if (!(range->flags & c->subtable_flags)) + continue; + } + const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs); if (replacement) { @@ -820,7 +839,7 @@ struct InsertionSubtable driver_context_t dc (this, c); StateTableDriver driver (machine, c->buffer, c->face); - driver.drive (&dc); + driver.drive (&dc, c); return_trace (dc.ret); } @@ -968,7 +987,7 @@ struct Chain // Check whether this type/setting pair was requested in the map, and if so, apply its flags. // (The search here only looks at the type and setting fields of feature_info_t.) hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 }; - if (map->features.bsearch (info)) + if (map->current_features.bsearch (info)) { flags &= feature.disableFlags; flags |= feature.enableFlags; @@ -980,13 +999,21 @@ struct Chain setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS; goto retry; } +#ifndef HB_NO_AAT + else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting && + /* TODO: Rudimentary language matching. */ + hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language)) + { + flags &= feature.disableFlags; + flags |= feature.enableFlags; + } +#endif } } return flags; } - void apply (hb_aat_apply_context_t *c, - hb_mask_t flags) const + void apply (hb_aat_apply_context_t *c) const { const ChainSubtable *subtable = &StructAfter> (featureZ.as_array (featureCount)); unsigned int count = subtableCount; @@ -994,8 +1021,10 @@ struct Chain { bool reverse; - if (!(subtable->subFeatureFlags & flags)) + if (hb_none (hb_iter (c->range_flags) | + hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); }))) goto skip; + c->subtable_flags = subtable->subFeatureFlags; if (!(subtable->get_coverage() & ChainSubtable::AllDirections) && HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != @@ -1034,7 +1063,7 @@ struct Chain bool (subtable->get_coverage () & ChainSubtable::Backwards) != HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); - if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index)) + if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index)) goto skip; if (reverse) @@ -1045,7 +1074,7 @@ struct Chain if (reverse) c->buffer->reverse (); - (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index); + (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index); if (unlikely (!c->buffer->successful)) return; @@ -1111,22 +1140,31 @@ struct mortmorx { const Chain *chain = &firstChain; unsigned int count = chainCount; + if (unlikely (!map->chain_flags.resize (count))) + return; for (unsigned int i = 0; i < count; i++) { - map->chain_flags.push (chain->compile_flags (mapper)); + map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper), + mapper->range_first, + mapper->range_last}); chain = &StructAfter> (*chain); } } - void apply (hb_aat_apply_context_t *c) const + void apply (hb_aat_apply_context_t *c, + const hb_aat_map_t &map) const { if (unlikely (!c->buffer->successful)) return; + + c->buffer->unsafe_to_concat (); + c->set_lookup_index (0); const Chain *chain = &firstChain; unsigned int count = chainCount; for (unsigned int i = 0; i < count; i++) { - chain->apply (c, c->plan->aat_map.chain_flags[i]); + c->range_flags = &map.chain_flags[i]; + chain->apply (c); if (unlikely (!c->buffer->successful)) return; chain = &StructAfter> (*chain); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-opbd-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-opbd-table.hh index 3054c76b96b..959382f356f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-opbd-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-opbd-table.hh @@ -42,7 +42,7 @@ struct OpticalBounds bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } FWORD leftSide; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh index d99a53b14c4..cb531283498 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout-trak-table.hh @@ -62,7 +62,7 @@ struct TrackTableEntry } protected: - HBFixed track; /* Track value for this record. */ + F16DOT16 track; /* Track value for this record. */ NameID trackNameID; /* The 'name' table index for this track. * (a short word or phrase like "loose" * or "very tight") */ @@ -82,7 +82,7 @@ struct TrackData const void *base) const { unsigned int sizes = nSizes; - hb_array_t size_table ((base+sizeTable).arrayZ, sizes); + hb_array_t size_table ((base+sizeTable).arrayZ, sizes); float s0 = size_table[idx].to_float (); float s1 = size_table[idx + 1].to_float (); @@ -120,7 +120,7 @@ struct TrackData if (!sizes) return 0.; if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes); - hb_array_t size_table ((base+sizeTable).arrayZ, sizes); + hb_array_t size_table ((base+sizeTable).arrayZ, sizes); unsigned int size_index; for (size_index = 0; size_index < sizes - 1; size_index++) if (size_table[size_index].to_float () >= ptem) @@ -141,7 +141,7 @@ struct TrackData protected: HBUINT16 nTracks; /* Number of separate tracks included in this table. */ HBUINT16 nSizes; /* Number of point sizes included in this table. */ - NNOffset32To> + NNOffset32To> sizeTable; /* Offset from start of the tracking table to * Array[nSizes] of size values.. */ UnsizedArrayOf diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc index a9a9ce6b326..b0afbdfbb04 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.cc @@ -131,6 +131,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] = {HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4}, {HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7}, {HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7}, + {HB_TAG ('r','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF}, {HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF}, {HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION}, {HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE}, @@ -229,7 +230,7 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, * * Note: does not examine the `GSUB` table. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 2.3.0 */ @@ -243,15 +244,23 @@ hb_aat_layout_has_substitution (hb_face_t *face) void hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, - hb_buffer_t *buffer) + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned num_features) { + hb_aat_map_builder_t builder (font->face, plan->props); + for (unsigned i = 0; i < num_features; i++) + builder.add_feature (features[i]); + hb_aat_map_t map; + builder.compile (map); + hb_blob_t *morx_blob = font->face->table.morx.get_blob (); const AAT::morx& morx = *morx_blob->as (); if (morx.has_data ()) { AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob); if (!buffer->message (font, "start table morx")) return; - morx.apply (&c); + morx.apply (&c, map); (void) buffer->message (font, "end table morx"); return; } @@ -262,7 +271,7 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, { AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob); if (!buffer->message (font, "start table mort")) return; - mort.apply (&c); + mort.apply (&c, map); (void) buffer->message (font, "end table mort"); return; } @@ -288,7 +297,7 @@ is_deleted_glyph (const hb_glyph_info_t *info) void hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer) { - hb_ot_layout_delete_glyphs_inplace (buffer, is_deleted_glyph); + buffer->delete_glyphs_inplace (is_deleted_glyph); } /** @@ -300,7 +309,7 @@ hb_aat_layout_remove_deleted_glyphs (hb_buffer_t *buffer) * * Note: does not examine the `GPOS` table. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 2.3.0 */ @@ -333,7 +342,7 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan, * Tests whether the specified face includes any tracking information * in the `trak` table. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 2.3.0 */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh index 1a95507ccee..36bb0ef07dd 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-layout.hh @@ -53,7 +53,9 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper, HB_INTERNAL void hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan, hb_font_t *font, - hb_buffer_t *buffer); + hb_buffer_t *buffer, + const hb_feature_t *features, + unsigned num_features); HB_INTERNAL void hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc index ad3eff7935f..122f29dc681 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.cc @@ -36,27 +36,29 @@ #include "hb-aat-layout-feat-table.hh" -void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) +void hb_aat_map_builder_t::add_feature (const hb_feature_t &feature) { if (!face->table.feat->has_data ()) return; - if (tag == HB_TAG ('a','a','l','t')) + if (feature.tag == HB_TAG ('a','a','l','t')) { if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES)) return; - feature_info_t *info = features.push(); - info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES; - info->setting = (hb_aat_layout_feature_selector_t) value; - info->seq = features.length; - info->is_exclusive = true; + feature_range_t *range = features.push(); + range->start = feature.start; + range->end = feature.end; + range->info.type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES; + range->info.setting = (hb_aat_layout_feature_selector_t) feature.value; + range->info.seq = features.length; + range->info.is_exclusive = true; return; } - const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag); + const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (feature.tag); if (!mapping) return; - const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType); - if (!feature->has_data ()) + const AAT::FeatureName* feature_name = &face->table.feat->get_feature (mapping->aatFeatureType); + if (!feature_name->has_data ()) { /* Special case: Chain::compile_flags will fall back to the deprecated version of * small-caps if necessary, so we need to check for that possibility. @@ -64,38 +66,106 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value) if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE && mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS) { - feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE); - if (!feature->has_data ()) return; + feature_name = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE); + if (!feature_name->has_data ()) return; } else return; } - feature_info_t *info = features.push(); - info->type = mapping->aatFeatureType; - info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable; - info->seq = features.length; - info->is_exclusive = feature->is_exclusive (); + feature_range_t *range = features.push(); + range->start = feature.start; + range->end = feature.end; + range->info.type = mapping->aatFeatureType; + range->info.setting = feature.value ? mapping->selectorToEnable : mapping->selectorToDisable; + range->info.seq = features.length; + range->info.is_exclusive = feature_name->is_exclusive (); } void hb_aat_map_builder_t::compile (hb_aat_map_t &m) { - /* Sort features and merge duplicates */ - if (features.length) + /* Compute active features per range, and compile each. */ + + /* Sort features by start/end events. */ + hb_vector_t feature_events; + for (unsigned int i = 0; i < features.length; i++) + { + auto &feature = features[i]; + + if (features[i].start == features[i].end) + continue; + + feature_event_t *event; + + event = feature_events.push (); + event->index = features[i].start; + event->start = true; + event->feature = feature.info; + + event = feature_events.push (); + event->index = features[i].end; + event->start = false; + event->feature = feature.info; + } + feature_events.qsort (); + /* Add a strategic final event. */ + { + feature_info_t feature; + feature.seq = features.length + 1; + + feature_event_t *event = feature_events.push (); + event->index = -1; /* This value does magic. */ + event->start = false; + event->feature = feature; + } + + /* Scan events and save features for each range. */ + hb_sorted_vector_t active_features; + unsigned int last_index = 0; + for (unsigned int i = 0; i < feature_events.length; i++) { - features.qsort (); - unsigned int j = 0; - for (unsigned int i = 1; i < features.length; i++) - if (features[i].type != features[j].type || - /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off - * respectively, so we mask out the low-order bit when checking for "duplicates" - * (selectors referring to the same feature setting) here. */ - (!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1)))) - features[++j] = features[i]; - features.shrink (j + 1); + feature_event_t *event = &feature_events[i]; + + if (event->index != last_index) + { + /* Save a snapshot of active features and the range. */ + + /* Sort features and merge duplicates */ + current_features = active_features; + range_first = last_index; + range_last = event->index - 1; + if (current_features.length) + { + current_features.qsort (); + unsigned int j = 0; + for (unsigned int i = 1; i < current_features.length; i++) + if (current_features[i].type != current_features[j].type || + /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off + * respectively, so we mask out the low-order bit when checking for "duplicates" + * (selectors referring to the same feature setting) here. */ + (!current_features[i].is_exclusive && ((current_features[i].setting & ~1) != (current_features[j].setting & ~1)))) + current_features[++j] = current_features[i]; + current_features.shrink (j + 1); + } + + hb_aat_layout_compile_map (this, &m); + + last_index = event->index; + } + + if (event->start) + { + active_features.push (event->feature); + } else { + feature_info_t *feature = active_features.lsearch (event->feature); + if (feature) + active_features.remove_ordered (feature - active_features.arrayZ); + } } - hb_aat_layout_compile_map (this, &m); + for (auto &chain_flags : m.chain_flags) + // With our above setup this value is one less than desired; adjust it. + chain_flags.tail().cluster_last = HB_FEATURE_GLOBAL_END; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh index ce30daa6084..b21f5bacb9e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-aat-map.hh @@ -35,16 +35,15 @@ struct hb_aat_map_t friend struct hb_aat_map_builder_t; public: - - void init () + struct range_flags_t { - memset (this, 0, sizeof (*this)); - chain_flags.init (); - } - void fini () { chain_flags.fini (); } + hb_mask_t flags; + unsigned cluster_first; + unsigned cluster_last; // end - 1 + }; public: - hb_vector_t chain_flags; + hb_vector_t> chain_flags; }; struct hb_aat_map_builder_t @@ -52,10 +51,11 @@ struct hb_aat_map_builder_t public: HB_INTERNAL hb_aat_map_builder_t (hb_face_t *face_, - const hb_segment_properties_t *props_ HB_UNUSED) : - face (face_) {} + const hb_segment_properties_t props_) : + face (face_), + props (props_) {} - HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1); + HB_INTERNAL void add_feature (const hb_feature_t &feature); HB_INTERNAL void compile (hb_aat_map_t &m); @@ -77,7 +77,7 @@ struct hb_aat_map_builder_t return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0); } - /* compares type & setting only, not is_exclusive flag or seq number */ + /* compares type & setting only */ int cmp (const feature_info_t& f) const { return (f.type != type) ? (f.type < type ? -1 : 1) : @@ -85,11 +85,38 @@ struct hb_aat_map_builder_t } }; + struct feature_range_t + { + feature_info_t info; + unsigned start; + unsigned end; + }; + + private: + struct feature_event_t + { + unsigned int index; + bool start; + feature_info_t feature; + + HB_INTERNAL static int cmp (const void *pa, const void *pb) { + const feature_event_t *a = (const feature_event_t *) pa; + const feature_event_t *b = (const feature_event_t *) pb; + return a->index < b->index ? -1 : a->index > b->index ? 1 : + a->start < b->start ? -1 : a->start > b->start ? 1 : + feature_info_t::cmp (&a->feature, &b->feature); + } + }; + public: hb_face_t *face; + hb_segment_properties_t props; public: - hb_sorted_vector_t features; + hb_sorted_vector_t features; + hb_sorted_vector_t current_features; + unsigned range_first = HB_FEATURE_GLOBAL_START; + unsigned range_last = HB_FEATURE_GLOBAL_END; }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh index 162601b380d..28dc036a515 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-algs.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-algs.hh @@ -109,15 +109,16 @@ struct BEInt struct __attribute__((packed)) packed_uint16_t { uint16_t v; }; constexpr operator Type () const { -#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ +#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ + ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ defined(__BYTE_ORDER) && \ (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) /* Spoon-feed the compiler a big-endian integer with alignment 1. * https://github.com/harfbuzz/harfbuzz/pull/1398 */ #if __BYTE_ORDER == __LITTLE_ENDIAN - return __builtin_bswap16 (((packed_uint16_t *) this)->v); + return __builtin_bswap16 (((packed_uint16_t *) v)->v); #else /* __BYTE_ORDER == __BIG_ENDIAN */ - return ((packed_uint16_t *) this)->v; + return ((packed_uint16_t *) v)->v; #endif #else return (v[0] << 8) @@ -153,15 +154,16 @@ struct BEInt struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; constexpr operator Type () const { -#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ +#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ + ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \ defined(__BYTE_ORDER) && \ (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN) /* Spoon-feed the compiler a big-endian integer with alignment 1. * https://github.com/harfbuzz/harfbuzz/pull/1398 */ #if __BYTE_ORDER == __LITTLE_ENDIAN - return __builtin_bswap32 (((packed_uint32_t *) this)->v); + return __builtin_bswap32 (((packed_uint32_t *) v)->v); #else /* __BYTE_ORDER == __BIG_ENDIAN */ - return ((packed_uint32_t *) this)->v; + return ((packed_uint32_t *) v)->v; #endif #else return (v[0] << 24) @@ -234,17 +236,6 @@ struct template constexpr auto impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) - template constexpr uint32_t - impl (const hb::shared_ptr& v, hb_priority<1>) const - { - return v.get () ? v.get ()->hash () : 0; - } - template constexpr uint32_t - impl (const hb::unique_ptr& v, hb_priority<1>) const - { - return v.get () ? v.get ()->hash () : 0; - } - template constexpr auto impl (const T& v, hb_priority<0>) const HB_RETURN (uint32_t, std::hash>{} (hb_deref (v))) @@ -493,6 +484,17 @@ struct } HB_FUNCOBJ (hb_equal); +struct +{ + template void + operator () (T& a, T& b) const + { + using std::swap; // allow ADL + swap (a, b); + } +} +HB_FUNCOBJ (hb_swap); + template struct hb_pair_t @@ -505,7 +507,7 @@ struct hb_pair_t hb_enable_if (std::is_default_constructible::value && std::is_default_constructible::value)> hb_pair_t () : first (), second () {} - hb_pair_t (T1 a, T2 b) : first (a), second (b) {} + hb_pair_t (T1 a, T2 b) : first (std::forward (a)), second (std::forward (b)) {} template (const pair_t& o) const { return first > o.first || (first == o.first && second > o.second); } bool operator <= (const pair_t& o) const { return !(*this > o); } + static int cmp (const void *pa, const void *pb) + { + pair_t *a = (pair_t *) pa; + pair_t *b = (pair_t *) pb; + + if (a->first < b->first) return -1; + if (a->first > b->first) return +1; + if (a->second < b->second) return -1; + if (a->second > b->second) return +1; + return 0; + } + + friend void swap (hb_pair_t& a, hb_pair_t& b) + { + hb_swap (a.first, b.first); + hb_swap (a.second, b.second); + } + + T1 first; T2 second; }; -#define hb_pair_t(T1,T2) hb_pair_t template static inline hb_pair_t hb_pair (T1&& a, T2&& b) { return hb_pair_t (a, b); } @@ -551,14 +571,14 @@ struct { template constexpr auto operator () (T&& a, T2&& b) const HB_AUTO_RETURN - (a <= b ? std::forward (a) : std::forward (b)) + (a <= b ? a : b) } HB_FUNCOBJ (hb_min); struct { template constexpr auto operator () (T&& a, T2&& b) const HB_AUTO_RETURN - (a >= b ? std::forward (a) : std::forward (b)) + (a >= b ? a : b) } HB_FUNCOBJ (hb_max); struct @@ -569,17 +589,6 @@ struct } HB_FUNCOBJ (hb_clamp); -struct -{ - template void - operator () (T& a, T& b) const - { - using std::swap; // allow ADL - swap (a, b); - } -} -HB_FUNCOBJ (hb_swap); - /* * Bithacks. */ @@ -848,19 +857,14 @@ hb_in_range (T u, T lo, T hi) return (T)(u - lo) <= (T)(hi - lo); } template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2) -{ - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2); -} -template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3) +hb_in_ranges (T u, T lo1, T hi1) { - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3); + return hb_in_range (u, lo1, hi1); } -template static inline bool -hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4) +template static inline bool +hb_in_ranges (T u, T lo1, T hi1, Ts... ds) { - return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3) || hb_in_range (u, lo4, hi4); + return hb_in_range (u, lo1, hi1) || hb_in_ranges (u, ds...); } @@ -868,10 +872,18 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3, T lo4, T hi4) * Overflow checking. */ -/* Consider __builtin_mul_overflow use here also */ static inline bool -hb_unsigned_mul_overflows (unsigned int count, unsigned int size) +hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr) { +#if (defined(__GNUC__) && (__GNUC__ >= 4)) || (defined(__clang__) && (__clang_major__ >= 8)) + unsigned stack_result; + if (!result) + result = &stack_result; + return __builtin_mul_overflow (count, size, result); +#endif + + if (result) + *result = count * size; return (size > 0) && (count >= ((unsigned int) -1) / size); } @@ -972,7 +984,7 @@ void hb_qsort(void *base, size_t nel, size_t width, [void *arg]); */ -#define SORT_R_SWAP(a,b,tmp) ((tmp) = (a), (a) = (b), (b) = (tmp)) +#define SORT_R_SWAP(a,b,tmp) ((void) ((tmp) = (a)), (void) ((a) = (b)), (b) = (tmp)) /* swap a and b */ /* a and b must not be equal! */ @@ -1163,9 +1175,12 @@ hb_qsort (void *base, size_t nel, size_t width, } -template static inline void -hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2) +template static inline void +hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *), T3 *array2 = nullptr) { + static_assert (hb_is_trivially_copy_assignable (T), ""); + static_assert (hb_is_trivially_copy_assignable (T3), ""); + for (unsigned int i = 1; i < len; i++) { unsigned int j = i; @@ -1188,12 +1203,6 @@ hb_stable_sort (T *array, unsigned int len, int(*compar)(const T2 *, const T2 *) } } -template static inline void -hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *)) -{ - hb_stable_sort (array, len, compar, (int *) nullptr); -} - static inline hb_bool_t hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out) { @@ -1321,47 +1330,4 @@ struct HB_FUNCOBJ (hb_dec); -/* Compiler-assisted vectorization. */ - -/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))), - * basically a fixed-size bitset. */ -template -struct hb_vector_size_t -{ - elt_t& operator [] (unsigned int i) { return v[i]; } - const elt_t& operator [] (unsigned int i) const { return v[i]; } - - void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); } - - template - hb_vector_size_t process (const Op& op) const - { - hb_vector_size_t r; - for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) - r.v[i] = op (v[i]); - return r; - } - template - hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const - { - hb_vector_size_t r; - for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) - r.v[i] = op (v[i], o.v[i]); - return r; - } - hb_vector_size_t operator | (const hb_vector_size_t &o) const - { return process (hb_bitwise_or, o); } - hb_vector_size_t operator & (const hb_vector_size_t &o) const - { return process (hb_bitwise_and, o); } - hb_vector_size_t operator ^ (const hb_vector_size_t &o) const - { return process (hb_bitwise_xor, o); } - hb_vector_size_t operator ~ () const - { return process (hb_bitwise_neg); } - - private: - static_assert (0 == byte_size % sizeof (elt_t), ""); - elt_t v[byte_size / sizeof (elt_t)]; -}; - - #endif /* HB_ALGS_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-array.hh b/src/java.desktop/share/native/libharfbuzz/hb-array.hh index 0a92392d319..08b25987061 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-array.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-array.hh @@ -100,10 +100,17 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> /* Ouch. The operator== compares the contents of the array. For range-based for loops, * it's best if we can just compare arrayZ, though comparing contents is still fast, * but also would require that Type has operator==. As such, we optimize this operator - * for range-based for loop and just compare arrayZ. No need to compare length, as we - * assume we're only compared to .end(). */ + * for range-based for loop and just compare arrayZ and length. + * + * The above comment is outdated now because we implemented separate begin/end to + * objects that were using hb_array_t for range-based loop before. */ bool operator != (const hb_array_t& o) const - { return arrayZ != o.arrayZ; } + { return this->arrayZ != o.arrayZ || this->length != o.length; } + + /* Faster range-based for loop without bounds-check. */ + Type *begin () const { return arrayZ; } + Type *end () const { return arrayZ + length; } + /* Extra operators. */ @@ -113,11 +120,11 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> HB_INTERNAL bool operator == (const hb_array_t &o) const; - uint32_t hash () const { + uint32_t hash () const + { uint32_t current = 0; - for (unsigned int i = 0; i < this->length; i++) { - current = current * 31 + hb_hash (this->arrayZ[i]); - } + for (auto &v : *this) + current = current * 31 + hb_hash (v); return current; } @@ -185,23 +192,18 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> hb_sorted_array_t qsort (int (*cmp_)(const void*, const void*)) { + //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), ""); if (likely (length)) hb_qsort (arrayZ, length, this->get_item_size (), cmp_); return hb_sorted_array_t (*this); } hb_sorted_array_t qsort () { + //static_assert (hb_enable_if (hb_is_trivially_copy_assignable(Type)), ""); if (likely (length)) hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp); return hb_sorted_array_t (*this); } - void qsort (unsigned int start, unsigned int end) - { - end = hb_min (end, length); - assert (start <= end); - if (likely (start < end)) - hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp); - } /* * Other methods. @@ -220,11 +222,8 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> if (end < start + 2) return; - for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) { - Type temp = arrayZ[rhs]; - arrayZ[rhs] = arrayZ[lhs]; - arrayZ[lhs] = temp; - } + for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) + hb_swap (arrayZ[rhs], arrayZ[lhs]); } hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const @@ -266,17 +265,31 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> void fini () { hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; } - template + template )))> hb_array_t copy (hb_serialize_context_t *c) const { TRACE_SERIALIZE (this); auto* out = c->start_embed (arrayZ); - if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ()); + if (unlikely (!c->extend_size (out, get_size (), false))) return_trace (hb_array_t ()); for (unsigned i = 0; i < length; i++) out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */ return_trace (hb_array_t (out, length)); } + template ))> + hb_array_t copy (hb_serialize_context_t *c) const + { + TRACE_SERIALIZE (this); + auto* out = c->start_embed (arrayZ); + if (unlikely (!c->extend_size (out, get_size (), false))) return_trace (hb_array_t ()); + hb_memcpy (out, arrayZ, get_size ()); + return_trace (hb_array_t (out, length)); + } + template bool sanitize (hb_sanitize_context_t *c) const { return c->check_array (arrayZ, length); } @@ -291,6 +304,9 @@ struct hb_array_t : hb_iter_with_fallback_t, Type&> unsigned int backwards_length = 0; }; template inline hb_array_t +hb_array () +{ return hb_array_t (); } +template inline hb_array_t hb_array (T *array, unsigned int length) { return hb_array_t (array, length); } template inline hb_array_t @@ -299,8 +315,8 @@ hb_array (T (&array_)[length_]) template struct hb_sorted_array_t : - hb_iter_t, Type&>, - hb_array_t + hb_array_t, + hb_iter_t, Type&> { typedef hb_iter_t iter_base_t; HB_ITER_USING (iter_base_t); @@ -320,17 +336,24 @@ struct hb_sorted_array_t : template constexpr hb_sorted_array_t (const hb_array_t &o) : - hb_iter_t (), - hb_array_t (o) {} + hb_array_t (o), + hb_iter_t () {} template hb_sorted_array_t& operator = (const hb_array_t &o) { hb_array_t (*this) = o; return *this; } /* Iterator implementation. */ + + /* See comment in hb_array_of::operator != */ bool operator != (const hb_sorted_array_t& o) const { return this->arrayZ != o.arrayZ || this->length != o.length; } + /* Faster range-based for loop without bounds-check. */ + Type *begin () const { return this->arrayZ; } + Type *end () const { return this->arrayZ + this->length; } + + hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const { return hb_sorted_array_t (((const hb_array_t *) (this))->sub_array (start_offset, seg_count)); } hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const @@ -344,7 +367,7 @@ struct hb_sorted_array_t : unsigned int i; return bfind (x, &i) ? &this->arrayZ[i] : not_found; } - template + template const Type *bsearch (const T &x, const Type *not_found = nullptr) const { unsigned int i; @@ -391,7 +414,7 @@ struct hb_sorted_array_t : this->length, sizeof (Type), _hb_cmp_method, - ds...); + std::forward (ds)...); } }; template inline hb_sorted_array_t @@ -423,18 +446,42 @@ inline bool hb_array_t::operator == (const hb_array_t -inline uint32_t hb_array_t::hash () const { +inline uint32_t hb_array_t::hash () const +{ uint32_t current = 0; - for (unsigned int i = 0; i < this->length; i++) - current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); + unsigned i = 0; + +#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ + ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) + struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + for (; i + 4 <= this->length; i += 4) + current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v); +#endif + + for (; i < this->length; i++) + current = current * 31 + hb_hash (this->arrayZ[i]); return current; } + template <> -inline uint32_t hb_array_t::hash () const { +inline uint32_t hb_array_t::hash () const +{ uint32_t current = 0; - for (unsigned int i = 0; i < this->length; i++) - current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u); + unsigned i = 0; + +#if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \ + ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) + struct __attribute__((packed)) packed_uint32_t { uint32_t v; }; + for (; i + 4 <= this->length; i += 4) + current = current * 31 + hb_hash ((uint32_t) ((packed_uint32_t *) &this->arrayZ[i])->v); +#endif + + for (; i < this->length; i++) + current = current * 31 + hb_hash (this->arrayZ[i]); return current; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh index 1267bc4fe20..57e94761e80 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-atomic.hh @@ -84,11 +84,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #define _hb_memory_r_barrier() std::atomic_thread_fence(std::memory_order_acquire) #define _hb_memory_w_barrier() std::atomic_thread_fence(std::memory_order_release) -#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) -#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast *> (AI)->store ((V), std::memory_order_relaxed)) -#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast *> (AI)->store ((V), std::memory_order_release)) -#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast const *> (AI)->load (std::memory_order_relaxed)) -#define hb_atomic_int_impl_get(AI) (reinterpret_cast const *> (AI)->load (std::memory_order_acquire)) +#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel)) +#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_relaxed)) +#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast::type> *> (AI)->store ((V), std::memory_order_release)) +#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_relaxed)) +#define hb_atomic_int_impl_get(AI) (reinterpret_cast::type> const *> (AI)->load (std::memory_order_acquire)) #define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast *> (P)->store ((V), std::memory_order_relaxed)) #define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast const *> (P)->load (std::memory_order_relaxed)) @@ -111,6 +111,24 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #endif +/* This should never be disabled, even under HB_NO_MT. + * except that MSVC gives me an internal compiler error, so disabled there. + * + * https://github.com/harfbuzz/harfbuzz/pull/4119 + */ +#ifndef _hb_compiler_memory_r_barrier +#if defined(__ATOMIC_ACQUIRE) // gcc-like +#define _hb_compiler_memory_r_barrier() asm volatile("": : :"memory") +#elif !defined(_MSC_VER) +#include +#define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire) +#else +#define _hb_compiler_memory_r_barrier() do {} while (0) +#endif +#endif + + + #ifndef _hb_memory_r_barrier #define _hb_memory_r_barrier() _hb_memory_barrier () #endif @@ -132,24 +150,47 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N) #endif #ifndef hb_atomic_int_impl_set inline void hb_atomic_int_impl_set (int *AI, int v) { _hb_memory_w_barrier (); *AI = v; } +inline void hb_atomic_int_impl_set (short *AI, short v) { _hb_memory_w_barrier (); *AI = v; } #endif #ifndef hb_atomic_int_impl_get inline int hb_atomic_int_impl_get (const int *AI) { int v = *AI; _hb_memory_r_barrier (); return v; } +inline short hb_atomic_int_impl_get (const short *AI) { short v = *AI; _hb_memory_r_barrier (); return v; } #endif #ifndef hb_atomic_ptr_impl_get inline void *hb_atomic_ptr_impl_get (void ** const P) { void *v = *P; _hb_memory_r_barrier (); return v; } #endif +struct hb_atomic_short_t +{ + hb_atomic_short_t () = default; + constexpr hb_atomic_short_t (short v) : v (v) {} + + hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; } + operator short () const { return get_relaxed (); } + + void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } + void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); } + short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); } + short get_acquire () const { return hb_atomic_int_impl_get (&v); } + short inc () { return hb_atomic_int_impl_add (&v, 1); } + short dec () { return hb_atomic_int_impl_add (&v, -1); } + + short v = 0; +}; + struct hb_atomic_int_t { hb_atomic_int_t () = default; constexpr hb_atomic_int_t (int v) : v (v) {} + hb_atomic_int_t& operator = (int v_) { set_relaxed (v_); return *this; } + operator int () const { return get_relaxed (); } + void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); } - void set (int v_) { hb_atomic_int_impl_set (&v, v_); } + void set_release (int v_) { hb_atomic_int_impl_set (&v, v_); } int get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); } - int get () const { return hb_atomic_int_impl_get (&v); } + int get_acquire () const { return hb_atomic_int_impl_get (&v); } int inc () { return hb_atomic_int_impl_add (&v, 1); } int dec () { return hb_atomic_int_impl_add (&v, -1); } @@ -167,11 +208,11 @@ struct hb_atomic_ptr_t void init (T* v_ = nullptr) { set_relaxed (v_); } void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); } T *get_relaxed () const { return (T *) hb_atomic_ptr_impl_get_relaxed (&v); } - T *get () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } + T *get_acquire () const { return (T *) hb_atomic_ptr_impl_get ((void **) &v); } bool cmpexch (const T *old, T *new_) const { return hb_atomic_ptr_impl_cmpexch ((void **) &v, (void *) old, (void *) new_); } - T * operator -> () const { return get (); } - template operator C * () const { return get (); } + T * operator -> () const { return get_acquire (); } + template operator C * () const { return get_acquire (); } T *v = nullptr; }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh index 5629ddc4cea..81e2a4997bd 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-page.hh @@ -30,32 +30,89 @@ #include "hb.hh" + +/* Compiler-assisted vectorization. */ + +/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))), + * basically a fixed-size bitset. We can't use the compiler type because hb_vector_t cannot + * guarantee alignment requirements. */ +template +struct hb_vector_size_t +{ + elt_t& operator [] (unsigned int i) { return v[i]; } + const elt_t& operator [] (unsigned int i) const { return v[i]; } + + void init0 () + { + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + v[i] = 0; + } + void init1 () + { + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + v[i] = (elt_t) -1; + } + + template + hb_vector_size_t process (const Op& op) const + { + hb_vector_size_t r; + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + r.v[i] = op (v[i]); + return r; + } + template + hb_vector_size_t process (const Op& op, const hb_vector_size_t &o) const + { + hb_vector_size_t r; + for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++) + r.v[i] = op (v[i], o.v[i]); + return r; + } + hb_vector_size_t operator | (const hb_vector_size_t &o) const + { return process (hb_bitwise_or, o); } + hb_vector_size_t operator & (const hb_vector_size_t &o) const + { return process (hb_bitwise_and, o); } + hb_vector_size_t operator ^ (const hb_vector_size_t &o) const + { return process (hb_bitwise_xor, o); } + hb_vector_size_t operator ~ () const + { return process (hb_bitwise_neg); } + + hb_array_t iter () const + { return hb_array (v); } + + private: + static_assert (0 == byte_size % sizeof (elt_t), ""); + elt_t v[byte_size / sizeof (elt_t)]; +}; + + struct hb_bit_page_t { - void init0 () { v.clear (); } - void init1 () { v.clear (0xFF); } + void init0 () { v.init0 (); } + void init1 () { v.init1 (); } - constexpr unsigned len () const + static inline constexpr unsigned len () { return ARRAY_LENGTH_CONST (v); } bool is_empty () const { - for (unsigned i = 0; i < len (); i++) - if (v[i]) - return false; - return true; + return + + hb_iter (v) + | hb_none + ; } uint32_t hash () const { - uint32_t h = 0; - for (unsigned i = 0; i < len (); i++) - h = h * 31 + hb_hash (v[i]); - return h; + return + + hb_iter (v) + | hb_reduce ([] (uint32_t h, const elt_t &_) { return h * 31 + hb_hash (_); }, (uint32_t) 0u) + ; } void add (hb_codepoint_t g) { elt (g) |= mask (g); } void del (hb_codepoint_t g) { elt (g) &= ~mask (g); } - void set (hb_codepoint_t g, bool v) { if (v) add (g); else del (g); } + void set (hb_codepoint_t g, bool value) { if (value) add (g); else del (g); } bool get (hb_codepoint_t g) const { return elt (g) & mask (g); } void add_range (hb_codepoint_t a, hb_codepoint_t b) @@ -69,7 +126,7 @@ struct hb_bit_page_t *la |= ~(mask (a) - 1); la++; - memset (la, 0xff, (char *) lb - (char *) la); + hb_memset (la, 0xff, (char *) lb - (char *) la); *lb |= ((mask (b) << 1) - 1); } @@ -85,7 +142,7 @@ struct hb_bit_page_t *la &= mask (a) - 1; la++; - memset (la, 0, (char *) lb - (char *) la); + hb_memset (la, 0, (char *) lb - (char *) la); *lb &= ~((mask (b) << 1) - 1); } @@ -101,13 +158,13 @@ struct hb_bit_page_t hb_codepoint_t *p, unsigned int size) const { - unsigned int start_v = start_value >> ELT_BITS_LOG_2; + unsigned int start_v = start_value / ELT_BITS; unsigned int start_bit = start_value & ELT_MASK; unsigned int count = 0; for (unsigned i = start_v; i < len () && count < size; i++) { elt_t bits = v[i]; - uint32_t v_base = base | (i << ELT_BITS_LOG_2); + uint32_t v_base = base | (i * ELT_BITS); for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++) { if ((elt_t(1) << j) & bits) { @@ -132,13 +189,13 @@ struct hb_bit_page_t unsigned int size, hb_codepoint_t *next_value) const { - unsigned int start_v = start_value >> ELT_BITS_LOG_2; + unsigned int start_v = start_value / ELT_BITS; unsigned int start_bit = start_value & ELT_MASK; unsigned int count = 0; for (unsigned i = start_v; i < len () && count < size; i++) { elt_t bits = v[i]; - uint32_t v_offset = i << ELT_BITS_LOG_2; + uint32_t v_offset = i * ELT_BITS; for (unsigned int j = start_bit; j < ELT_BITS && count < size; j++) { if ((elt_t(1) << j) & bits) @@ -161,7 +218,10 @@ struct hb_bit_page_t bool is_equal (const hb_bit_page_t &other) const { - return 0 == hb_memcmp (&v, &other.v, sizeof (v)); + for (unsigned i = 0; i < len (); i++) + if (v[i] != other.v[i]) + return false; + return true; } bool is_subset (const hb_bit_page_t &larger_page) const { @@ -173,10 +233,10 @@ struct hb_bit_page_t unsigned int get_population () const { - unsigned int pop = 0; - for (unsigned int i = 0; i < len (); i++) - pop += hb_popcount (v[i]); - return pop; + return + + hb_iter (v) + | hb_reduce ([] (unsigned pop, const elt_t &_) { return pop + hb_popcount (_); }, 0u) + ; } bool next (hb_codepoint_t *codepoint) const @@ -250,10 +310,10 @@ struct hb_bit_page_t static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID; typedef unsigned long long elt_t; - static constexpr unsigned PAGE_BITS = 512; - static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); - static constexpr unsigned PAGE_BITS_LOG_2 = 9; + static constexpr unsigned PAGE_BITS_LOG_2 = 9; // 512 bits + static constexpr unsigned PAGE_BITS = 1 << PAGE_BITS_LOG_2; static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, ""); + static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, ""); static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1; static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); } @@ -262,8 +322,6 @@ struct hb_bit_page_t typedef hb_vector_size_t vector_t; static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8; - static constexpr unsigned ELT_BITS_LOG_2 = 6; - static_assert (1 << ELT_BITS_LOG_2 == ELT_BITS, ""); static constexpr unsigned ELT_MASK = ELT_BITS - 1; static constexpr unsigned BITS = sizeof (vector_t) * 8; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh index 9562ca36a32..bf5a0b446de 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set-invertible.hh @@ -74,6 +74,11 @@ struct hb_bit_set_invertible_t inverted = !inverted; } + bool is_inverted () const + { + return inverted; + } + bool is_empty () const { hb_codepoint_t v = INVALID; @@ -123,10 +128,8 @@ struct hb_bit_set_invertible_t bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; } /* Has interface. */ - static constexpr bool SENTINEL = false; - typedef bool value_t; - value_t operator [] (hb_codepoint_t k) const { return get (k); } - bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + bool operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k]; } /* Predicate. */ bool operator () (hb_codepoint_t k) const { return has (k); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh index be244835a15..337bbe6b632 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-bit-set.hh @@ -38,7 +38,7 @@ struct hb_bit_set_t hb_bit_set_t () = default; ~hb_bit_set_t () = default; - hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); } + hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); } hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); } hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; } hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; } @@ -56,7 +56,7 @@ struct hb_bit_set_t { successful = true; population = 0; - last_page_lookup.set_relaxed (0); + last_page_lookup = 0; page_map.init (); pages.init (); } @@ -85,12 +85,16 @@ struct hb_bit_set_t void err () { if (successful) successful = false; } /* TODO Remove */ bool in_error () const { return !successful; } - bool resize (unsigned int count) + bool resize (unsigned int count, bool clear = true, bool exact_size = false) { if (unlikely (!successful)) return false; - if (unlikely (!pages.resize (count) || !page_map.resize (count))) + + if (pages.length == 0 && count == 1) + exact_size = true; // Most sets are small and local + + if (unlikely (!pages.resize (count, clear, exact_size) || !page_map.resize (count, clear, exact_size))) { - pages.resize (page_map.length); + pages.resize (page_map.length, clear, exact_size); successful = false; return false; } @@ -330,10 +334,8 @@ struct hb_bit_set_t } /* Has interface. */ - static constexpr bool SENTINEL = false; - typedef bool value_t; - value_t operator [] (hb_codepoint_t k) const { return get (k); } - bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; } + bool operator [] (hb_codepoint_t k) const { return get (k); } + bool has (hb_codepoint_t k) const { return (*this)[k]; } /* Predicate. */ bool operator () (hb_codepoint_t k) const { return has (k); } @@ -348,11 +350,11 @@ struct hb_bit_set_t hb_codepoint_t c = first - 1; return next (&c) && c <= last; } - void set (const hb_bit_set_t &other) + void set (const hb_bit_set_t &other, bool exact_size = false) { if (unlikely (!successful)) return; unsigned int count = other.pages.length; - if (unlikely (!resize (count))) + if (unlikely (!resize (count, false, exact_size))) return; population = other.population; @@ -391,7 +393,7 @@ struct hb_bit_set_t bool is_subset (const hb_bit_set_t &larger_set) const { if (has_population () && larger_set.has_population () && - population != larger_set.population) + population > larger_set.population) return false; uint32_t spi = 0; @@ -424,7 +426,7 @@ struct hb_bit_set_t private: bool allocate_compact_workspace (hb_vector_t& workspace) { - if (unlikely (!workspace.resize (pages.length))) + if (unlikely (!workspace.resize_exact (pages.length))) { successful = false; return false; @@ -465,12 +467,10 @@ struct hb_bit_set_t } public: - template - void process (const Op& op, const hb_bit_set_t &other) + void process_ (hb_bit_page_t::vector_t (*op) (const hb_bit_page_t::vector_t &, const hb_bit_page_t::vector_t &), + bool passthru_left, bool passthru_right, + const hb_bit_set_t &other) { - const bool passthru_left = op (1, 0); - const bool passthru_right = op (0, 1); - if (unlikely (!successful)) return; dirty (); @@ -542,21 +542,21 @@ struct hb_bit_set_t b = nb; for (; a && b; ) { - if (page_map[a - 1].major == other.page_map[b - 1].major) + if (page_map.arrayZ[a - 1].major == other.page_map.arrayZ[b - 1].major) { a--; b--; count--; - page_map[count] = page_map[a]; + page_map.arrayZ[count] = page_map.arrayZ[a]; page_at (count).v = op (page_at (a).v, other.page_at (b).v); } - else if (page_map[a - 1].major > other.page_map[b - 1].major) + else if (page_map.arrayZ[a - 1].major > other.page_map.arrayZ[b - 1].major) { a--; if (passthru_left) { count--; - page_map[count] = page_map[a]; + page_map.arrayZ[count] = page_map.arrayZ[a]; } } else @@ -565,8 +565,8 @@ struct hb_bit_set_t if (passthru_right) { count--; - page_map[count].major = other.page_map[b].major; - page_map[count].index = next_page++; + page_map.arrayZ[count].major = other.page_map.arrayZ[b].major; + page_map.arrayZ[count].index = next_page++; page_at (count).v = other.page_at (b).v; } } @@ -576,20 +576,29 @@ struct hb_bit_set_t { a--; count--; - page_map[count] = page_map [a]; + page_map.arrayZ[count] = page_map.arrayZ[a]; } if (passthru_right) while (b) { b--; count--; - page_map[count].major = other.page_map[b].major; - page_map[count].index = next_page++; + page_map.arrayZ[count].major = other.page_map.arrayZ[b].major; + page_map.arrayZ[count].index = next_page++; page_at (count).v = other.page_at (b).v; } assert (!count); resize (newCount); } + template + static hb_bit_page_t::vector_t + op_ (const hb_bit_page_t::vector_t &a, const hb_bit_page_t::vector_t &b) + { return Op{} (a, b); } + template + void process (const Op& op, const hb_bit_set_t &other) + { + process_ (op_, op (1, 0), op (0, 1), other); + } void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); } void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); } @@ -598,8 +607,6 @@ struct hb_bit_set_t bool next (hb_codepoint_t *codepoint) const { - // TODO: this should be merged with prev() as both implementations - // are very similar. if (unlikely (*codepoint == INVALID)) { *codepoint = get_min (); return *codepoint != INVALID; @@ -607,7 +614,7 @@ struct hb_bit_set_t const auto* page_map_array = page_map.arrayZ; unsigned int major = get_major (*codepoint); - unsigned int i = last_page_lookup.get_relaxed (); + unsigned int i = last_page_lookup; if (unlikely (i >= page_map.length || page_map_array[i].major != major)) { @@ -625,7 +632,7 @@ struct hb_bit_set_t if (pages_array[current.index].next (codepoint)) { *codepoint += current.major * page_t::PAGE_BITS; - last_page_lookup.set_relaxed (i); + last_page_lookup = i; return true; } i++; @@ -633,16 +640,16 @@ struct hb_bit_set_t for (; i < page_map.length; i++) { - const page_map_t ¤t = page_map.arrayZ[i]; + const page_map_t ¤t = page_map_array[i]; hb_codepoint_t m = pages_array[current.index].get_min (); if (m != INVALID) { *codepoint = current.major * page_t::PAGE_BITS + m; - last_page_lookup.set_relaxed (i); + last_page_lookup = i; return true; } } - last_page_lookup.set_relaxed (0); + last_page_lookup = 0; *codepoint = INVALID; return false; } @@ -656,21 +663,21 @@ struct hb_bit_set_t page_map_t map = {get_major (*codepoint), 0}; unsigned int i; page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST); - if (i < page_map.length && page_map[i].major == map.major) + if (i < page_map.length && page_map.arrayZ[i].major == map.major) { - if (pages[page_map[i].index].previous (codepoint)) + if (pages[page_map.arrayZ[i].index].previous (codepoint)) { - *codepoint += page_map[i].major * page_t::PAGE_BITS; + *codepoint += page_map.arrayZ[i].major * page_t::PAGE_BITS; return true; } } i--; for (; (int) i >= 0; i--) { - hb_codepoint_t m = pages[page_map[i].index].get_max (); + hb_codepoint_t m = pages.arrayZ[page_map.arrayZ[i].index].get_max (); if (m != INVALID) { - *codepoint = page_map[i].major * page_t::PAGE_BITS + m; + *codepoint = page_map.arrayZ[i].major * page_t::PAGE_BITS + m; return true; } } @@ -725,7 +732,7 @@ struct hb_bit_set_t { const auto* page_map_array = page_map.arrayZ; unsigned int major = get_major (codepoint); - unsigned int i = last_page_lookup.get_relaxed (); + unsigned int i = last_page_lookup; if (unlikely (i >= page_map.length || page_map_array[i].major != major)) { page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST); @@ -766,7 +773,7 @@ struct hb_bit_set_t { const auto* page_map_array = page_map.arrayZ; unsigned int major = get_major (codepoint); - unsigned int i = last_page_lookup.get_relaxed (); + unsigned int i = last_page_lookup; if (unlikely (i >= page_map.length || page_map_array[i].major != major)) { page_map.bfind(major, &i, HB_NOT_FOUND_STORE_CLOSEST); @@ -893,12 +900,12 @@ struct hb_bit_set_t /* The extra page_map length is necessary; can't just rely on vector here, * since the next check would be tricked because a null page also has * major==0, which we can't distinguish from an actualy major==0 page... */ - unsigned i = last_page_lookup.get_relaxed (); + unsigned i = last_page_lookup; if (likely (i < page_map.length)) { auto &cached_page = page_map.arrayZ[i]; if (cached_page.major == major) - return &pages[cached_page.index]; + return &pages.arrayZ[cached_page.index]; } page_map_t map = {major, pages.length}; @@ -910,15 +917,15 @@ struct hb_bit_set_t if (unlikely (!resize (pages.length + 1))) return nullptr; - pages[map.index].init0 (); - memmove (page_map + i + 1, - page_map + i, + pages.arrayZ[map.index].init0 (); + memmove (page_map.arrayZ + i + 1, + page_map.arrayZ + i, (page_map.length - 1 - i) * page_map.item_size); page_map[i] = map; } - last_page_lookup.set_relaxed (i); - return &pages[page_map[i].index]; + last_page_lookup = i; + return &pages.arrayZ[page_map.arrayZ[i].index]; } const page_t *page_for (hb_codepoint_t g) const { @@ -927,23 +934,31 @@ struct hb_bit_set_t /* The extra page_map length is necessary; can't just rely on vector here, * since the next check would be tricked because a null page also has * major==0, which we can't distinguish from an actualy major==0 page... */ - unsigned i = last_page_lookup.get_relaxed (); + unsigned i = last_page_lookup; if (likely (i < page_map.length)) { auto &cached_page = page_map.arrayZ[i]; if (cached_page.major == major) - return &pages[cached_page.index]; + return &pages.arrayZ[cached_page.index]; } page_map_t key = {major}; if (!page_map.bfind (key, &i)) return nullptr; - last_page_lookup.set_relaxed (i); - return &pages[page_map[i].index]; + last_page_lookup = i; + return &pages.arrayZ[page_map[i].index]; + } + page_t &page_at (unsigned int i) + { + assert (i < page_map.length); + return pages.arrayZ[page_map.arrayZ[i].index]; + } + const page_t &page_at (unsigned int i) const + { + assert (i < page_map.length); + return pages.arrayZ[page_map.arrayZ[i].index]; } - page_t &page_at (unsigned int i) { return pages[page_map[i].index]; } - const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; } unsigned int get_major (hb_codepoint_t g) const { return g >> page_t::PAGE_BITS_LOG_2; } unsigned int page_remainder (hb_codepoint_t g) const { return g & page_t::PAGE_BITMASK; } hb_codepoint_t major_start (unsigned int major) const { return major << page_t::PAGE_BITS_LOG_2; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.cc b/src/java.desktop/share/native/libharfbuzz/hb-blob.cc index 1ee4195db7f..2a43afa1a43 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-blob.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.cc @@ -99,7 +99,7 @@ hb_blob_create (const char *data, * is zero. This is in contrast to hb_blob_create(), which returns the singleton * empty blob (as returned by hb_blob_get_empty()) if @length is zero. * - * Return value: New blob, or %NULL if failed. Destroy with hb_blob_destroy(). + * Return value: New blob, or `NULL` if failed. Destroy with hb_blob_destroy(). * * Since: 2.8.2 **/ @@ -263,8 +263,6 @@ hb_blob_destroy (hb_blob_t *blob) { if (!hb_object_destroy (blob)) return; - blob->fini_shallow (); - hb_free (blob); } @@ -278,7 +276,7 @@ hb_blob_destroy (hb_blob_t *blob) * * Attaches a user-data key/data pair to the specified blob. * - * Return value: %true if success, %false otherwise + * Return value: `true` if success, `false` otherwise * * Since: 0.9.2 **/ @@ -305,7 +303,7 @@ hb_blob_set_user_data (hb_blob_t *blob, * Since: 0.9.2 **/ void * -hb_blob_get_user_data (hb_blob_t *blob, +hb_blob_get_user_data (const hb_blob_t *blob, hb_user_data_key_t *key) { return hb_object_get_user_data (blob, key); @@ -335,7 +333,7 @@ hb_blob_make_immutable (hb_blob_t *blob) * * Tests whether a blob is immutable. * - * Return value: %true if @blob is immutable, %false otherwise + * Return value: `true` if @blob is immutable, `false` otherwise * * Since: 0.9.2 **/ @@ -394,7 +392,7 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length) * fails. * * Returns: (transfer none) (array length=length): Writable blob data, - * or %NULL if failed. + * or `NULL` if failed. * * Since: 0.9.2 **/ @@ -497,7 +495,7 @@ hb_blob_t::try_make_writable () DEBUG_MSG_FUNC (BLOB, this, "dupped successfully -> %p\n", this->data); - memcpy (new_data, this->data, this->length); + hb_memcpy (new_data, this->data, this->length); this->destroy_user_data (); this->mode = HB_MEMORY_MODE_WRITABLE; this->data = new_data; @@ -620,7 +618,7 @@ hb_blob_create_from_file (const char *file_name) * specified binary font file. * * Returns: An #hb_blob_t pointer with the content of the file, - * or %NULL if failed. + * or `NULL` if failed. * * Since: 2.8.2 **/ @@ -678,7 +676,7 @@ hb_blob_create_from_file_or_fail (const char *file_name) wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size); if (unlikely (!wchar_file_name)) goto fail_without_close; mbstowcs (wchar_file_name, file_name, size); -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) { CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 }; ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS); @@ -699,7 +697,7 @@ hb_blob_create_from_file_or_fail (const char *file_name) if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close; -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) { LARGE_INTEGER length; GetFileSizeEx (fd, &length); @@ -712,7 +710,7 @@ hb_blob_create_from_file_or_fail (const char *file_name) #endif if (unlikely (!file->mapping)) goto fail; -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0); #else file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.h b/src/java.desktop/share/native/libharfbuzz/hb-blob.h index 860b09bd088..b737665d93f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-blob.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.h @@ -135,7 +135,7 @@ hb_blob_set_user_data (hb_blob_t *blob, HB_EXTERN void * -hb_blob_get_user_data (hb_blob_t *blob, +hb_blob_get_user_data (const hb_blob_t *blob, hb_user_data_key_t *key); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-blob.hh b/src/java.desktop/share/native/libharfbuzz/hb-blob.hh index a3683a681e7..b1b3b94d3dd 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-blob.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-blob.hh @@ -38,7 +38,7 @@ struct hb_blob_t { - void fini_shallow () { destroy_user_data (); } + ~hb_blob_t () { destroy_user_data (); } void destroy_user_data () { @@ -61,12 +61,12 @@ struct hb_blob_t public: hb_object_header_t header; - const char *data; - unsigned int length; - hb_memory_mode_t mode; + const char *data = nullptr; + unsigned int length = 0; + hb_memory_mode_t mode = (hb_memory_mode_t) 0; - void *user_data; - hb_destroy_func_t destroy; + void *user_data = nullptr; + hb_destroy_func_t destroy = nullptr; }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh index 970fae7dfa6..7b9fc557f73 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-json.hh @@ -32,35 +32,38 @@ #include "hb.hh" -#line 36 "hb-buffer-deserialize-json.hh" +#line 33 "hb-buffer-deserialize-json.hh" static const unsigned char _deserialize_json_trans_keys[] = { 0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, - 48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, - 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, - 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, - 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, - 34u, 92u, 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, - 9u, 125u, 9u, 93u, 9u, 123u, 0u, 0u, 0 + 48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, + 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, + 9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, + 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, + 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, + 9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, + 9u, 123u, 0u, 0u, 0 }; static const char _deserialize_json_key_spans[] = { 0, 115, 26, 21, 2, 1, 50, 49, - 10, 117, 117, 117, 1, 50, 49, 10, - 117, 117, 1, 1, 50, 49, 117, 117, - 2, 1, 50, 49, 10, 117, 117, 1, - 50, 49, 10, 117, 117, 1, 50, 49, - 59, 117, 59, 117, 117, 1, 50, 49, - 117, 85, 115, 0 + 10, 117, 117, 85, 117, 1, 50, 49, + 10, 117, 117, 1, 1, 50, 49, 117, + 117, 2, 1, 50, 49, 10, 117, 117, + 1, 50, 49, 10, 117, 117, 1, 1, + 50, 49, 117, 117, 1, 50, 49, 59, + 117, 59, 117, 117, 1, 50, 49, 117, + 115, 0 }; static const short _deserialize_json_index_offsets[] = { 0, 0, 116, 143, 165, 168, 170, 221, - 271, 282, 400, 518, 636, 638, 689, 739, - 750, 868, 986, 988, 990, 1041, 1091, 1209, - 1327, 1330, 1332, 1383, 1433, 1444, 1562, 1680, - 1682, 1733, 1783, 1794, 1912, 2030, 2032, 2083, - 2133, 2193, 2311, 2371, 2489, 2607, 2609, 2660, - 2710, 2828, 2914, 3030 + 271, 282, 400, 518, 604, 722, 724, 775, + 825, 836, 954, 1072, 1074, 1076, 1127, 1177, + 1295, 1413, 1416, 1418, 1469, 1519, 1530, 1648, + 1766, 1768, 1819, 1869, 1880, 1998, 2116, 2118, + 2120, 2171, 2221, 2339, 2457, 2459, 2510, 2560, + 2620, 2738, 2798, 2916, 3034, 3036, 3087, 3137, + 3255, 3371 }; static const char _deserialize_json_indicies[] = { @@ -82,28 +85,28 @@ static const char _deserialize_json_indicies[] = { 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 4, 1, - 5, 1, 6, 7, 1, 1, 8, 1, + 5, 1, 6, 7, 1, 8, 9, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 9, 1, 10, 11, - 1, 12, 1, 12, 12, 12, 12, 12, + 1, 1, 1, 1, 10, 1, 11, 12, + 1, 13, 1, 13, 13, 13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 12, 1, 1, 1, 1, 1, + 1, 1, 13, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 13, 1, 13, 13, - 13, 13, 13, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 14, 1, 14, 14, + 14, 14, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 13, 1, 1, + 1, 1, 1, 1, 1, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 14, 1, 1, 15, 16, 16, - 16, 16, 16, 16, 16, 16, 16, 1, - 17, 18, 18, 18, 18, 18, 18, 18, - 18, 18, 1, 19, 19, 19, 19, 19, + 1, 1, 15, 1, 1, 16, 17, 17, + 17, 17, 17, 17, 17, 17, 17, 1, + 18, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 1, 20, 20, 20, 20, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 19, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 20, 1, + 1, 1, 20, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 21, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -113,11 +116,11 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 21, - 1, 22, 22, 22, 22, 22, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 22, + 1, 23, 23, 23, 23, 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 22, 1, 1, 1, 1, 1, 1, 1, + 23, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -128,85 +131,94 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 23, 1, 19, - 19, 19, 19, 19, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 24, 1, 25, + 25, 25, 25, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 19, 1, + 1, 1, 1, 1, 1, 1, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 20, 1, 1, 1, 18, 18, - 18, 18, 18, 18, 18, 18, 18, 18, + 1, 1, 26, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 27, 1, 20, 20, 20, + 20, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 21, 1, 1, 1, 19, 19, 19, 19, + 19, 19, 19, 19, 19, 19, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 21, 1, 24, 1, 24, - 24, 24, 24, 24, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 24, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 25, 1, 25, 25, 25, 25, 25, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 25, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 26, 1, - 1, 27, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 1, 29, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 1, 31, - 31, 31, 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 31, 1, + 1, 22, 1, 28, 1, 28, 28, 28, + 28, 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 32, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 28, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 29, 1, + 29, 29, 29, 29, 29, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 29, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 30, 1, 1, 31, + 32, 32, 32, 32, 32, 32, 32, 32, + 32, 1, 33, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 1, 35, 35, 35, + 35, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 36, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 33, 1, 31, 31, 31, - 31, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 32, 1, 1, 1, 30, 30, 30, 30, - 30, 30, 30, 30, 30, 30, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 37, 1, 35, 35, 35, 35, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 35, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 36, 1, + 1, 1, 34, 34, 34, 34, 34, 34, + 34, 34, 34, 34, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 33, 1, 34, 1, 35, 1, 35, - 35, 35, 35, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 35, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 36, 1, 36, 36, 36, 36, 36, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 37, + 1, 38, 1, 39, 1, 39, 39, 39, + 39, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 36, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 37, 38, 38, 38, 38, 38, 38, - 38, 38, 38, 1, 39, 39, 39, 39, - 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 39, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 40, 1, + 40, 40, 40, 40, 40, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 40, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 41, + 42, 42, 42, 42, 42, 42, 42, 42, + 42, 1, 43, 43, 43, 43, 43, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 43, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 44, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -215,43 +227,42 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 41, 1, 39, 39, 39, 39, 39, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 45, 1, + 43, 43, 43, 43, 43, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 39, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 40, 1, 1, - 1, 42, 42, 42, 42, 42, 42, 42, - 42, 42, 42, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 43, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 44, 1, 1, 1, 46, + 46, 46, 46, 46, 46, 46, 46, 46, + 46, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 41, 1, - 43, 44, 1, 45, 1, 45, 45, 45, - 45, 45, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 45, 1, 1, 1, + 1, 1, 1, 1, 45, 1, 47, 48, + 1, 49, 1, 49, 49, 49, 49, 49, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 46, 1, - 46, 46, 46, 46, 46, 1, 1, 1, + 1, 1, 49, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 46, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 47, 1, 1, 48, - 49, 49, 49, 49, 49, 49, 49, 49, - 49, 1, 50, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 1, 52, 52, 52, - 52, 52, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 50, 1, 50, 50, + 50, 50, 50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 52, 1, 1, 1, + 1, 1, 1, 1, 1, 50, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 53, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 51, 1, 1, 52, 53, 53, + 53, 53, 53, 53, 53, 53, 53, 1, + 54, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 1, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 56, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 57, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -259,42 +270,43 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 54, 1, 52, 52, 52, 52, 52, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 52, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 53, 1, - 1, 1, 51, 51, 51, 51, 51, 51, - 51, 51, 51, 51, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 58, + 1, 56, 56, 56, 56, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 56, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 57, 1, 1, 1, + 55, 55, 55, 55, 55, 55, 55, 55, + 55, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 54, - 1, 55, 1, 55, 55, 55, 55, 55, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 55, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 58, 1, 59, + 1, 59, 59, 59, 59, 59, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 56, 1, 56, 56, - 56, 56, 56, 1, 1, 1, 1, 1, + 59, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 56, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 57, 1, 1, 58, 59, 59, - 59, 59, 59, 59, 59, 59, 59, 1, - 60, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 1, 62, 62, 62, 62, 62, + 1, 1, 60, 1, 60, 60, 60, 60, + 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 60, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 62, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 63, 1, + 61, 1, 1, 62, 63, 63, 63, 63, + 63, 63, 63, 63, 63, 1, 64, 65, + 65, 65, 65, 65, 65, 65, 65, 65, + 1, 66, 66, 66, 66, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 66, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 67, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -302,48 +314,42 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 64, - 1, 62, 62, 62, 62, 62, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 62, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 63, 1, 1, 1, - 61, 61, 61, 61, 61, 61, 61, 61, - 61, 61, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 68, 1, 66, + 66, 66, 66, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 67, 1, 1, 1, 65, 65, + 65, 65, 65, 65, 65, 65, 65, 65, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 64, 1, 65, - 1, 65, 65, 65, 65, 65, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 65, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 68, 1, 69, 1, 70, + 1, 70, 70, 70, 70, 70, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 70, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 66, 1, 66, 66, 66, 66, - 66, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 66, 1, 67, 1, 1, + 1, 1, 71, 1, 71, 71, 71, 71, + 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 68, 69, 69, 69, 69, - 69, 69, 69, 69, 69, 1, 71, 70, - 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, - 70, 70, 70, 70, 70, 70, 70, 70, - 72, 70, 73, 73, 73, 73, 73, 1, + 1, 1, 1, 71, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 72, 73, 73, 73, 73, + 73, 73, 73, 73, 73, 1, 74, 74, + 74, 74, 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 73, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 74, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 75, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -352,86 +358,126 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 75, 1, - 70, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 76, 1, 74, 74, 74, 74, + 74, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 74, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 75, + 1, 1, 1, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 76, 1, 78, 1, 78, 78, 78, 78, + 78, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 78, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 79, 1, 79, + 79, 79, 79, 79, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 79, 1, + 80, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 81, 82, + 82, 82, 82, 82, 82, 82, 82, 82, + 1, 84, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 85, 83, 86, 86, 86, + 86, 86, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 86, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 87, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 70, 1, 76, 76, 76, 76, - 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 76, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 77, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 88, 1, 83, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 83, 1, 89, + 89, 89, 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 90, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 78, 1, 76, 76, 76, 76, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 76, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 77, 1, 1, - 1, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 91, 1, 89, 89, 89, + 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 78, 1, - 80, 1, 80, 80, 80, 80, 80, 1, + 1, 1, 1, 1, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 90, 1, 1, 1, 92, 92, 92, 92, + 92, 92, 92, 92, 92, 92, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 80, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 81, 1, 81, 81, 81, - 81, 81, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 81, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 82, 83, 83, 83, - 83, 83, 83, 83, 83, 83, 1, 76, - 76, 76, 76, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 76, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 77, 1, 1, 1, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 91, 1, 93, 1, 93, 93, 93, + 93, 93, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 93, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 94, 1, + 94, 94, 94, 94, 94, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 94, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 95, + 96, 96, 96, 96, 96, 96, 96, 96, + 96, 1, 89, 89, 89, 89, 89, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 78, 1, 85, 85, 85, - 85, 85, 1, 1, 1, 1, 1, 1, + 1, 89, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 90, 1, 1, + 1, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 85, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 86, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 87, 1, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 91, 1, + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -442,46 +488,49 @@ static const char _deserialize_json_indicies[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 2, 1, 1, - 0 + 1, 1, 2, 1, 1, 0 }; static const char _deserialize_json_trans_targs[] = { - 1, 0, 2, 2, 3, 4, 18, 24, - 37, 45, 5, 12, 6, 7, 8, 9, - 11, 9, 11, 10, 2, 49, 10, 49, - 13, 14, 15, 16, 17, 16, 17, 10, - 2, 49, 19, 20, 21, 22, 23, 10, - 2, 49, 23, 25, 31, 26, 27, 28, - 29, 30, 29, 30, 10, 2, 49, 32, - 33, 34, 35, 36, 35, 36, 10, 2, - 49, 38, 39, 40, 43, 44, 40, 41, - 42, 10, 2, 49, 10, 2, 49, 44, - 46, 47, 43, 48, 48, 49, 50, 51 + 1, 0, 2, 2, 3, 4, 19, 25, + 38, 44, 52, 5, 13, 6, 7, 8, + 9, 12, 9, 12, 10, 2, 11, 10, + 11, 11, 56, 57, 14, 15, 16, 17, + 18, 17, 18, 10, 2, 11, 20, 21, + 22, 23, 24, 10, 2, 11, 24, 26, + 32, 27, 28, 29, 30, 31, 30, 31, + 10, 2, 11, 33, 34, 35, 36, 37, + 36, 37, 10, 2, 11, 39, 40, 41, + 42, 43, 10, 2, 11, 43, 45, 46, + 47, 50, 51, 47, 48, 49, 10, 2, + 11, 10, 2, 11, 51, 53, 54, 50, + 55, 55 }; static const char _deserialize_json_trans_actions[] = { 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 2, - 2, 0, 0, 3, 3, 4, 0, 5, - 0, 0, 2, 2, 2, 0, 0, 6, - 6, 7, 0, 0, 0, 2, 2, 8, - 8, 9, 0, 0, 0, 0, 0, 2, - 2, 2, 0, 0, 10, 10, 11, 0, - 0, 2, 2, 2, 0, 0, 12, 12, - 13, 0, 0, 2, 14, 14, 0, 15, - 0, 16, 16, 17, 18, 18, 19, 15, - 0, 0, 20, 20, 21, 0, 0, 0 + 0, 0, 0, 0, 0, 0, 0, 2, + 2, 2, 0, 0, 3, 3, 4, 0, + 5, 0, 0, 0, 0, 0, 2, 2, + 2, 0, 0, 6, 6, 7, 0, 0, + 0, 2, 2, 8, 8, 9, 0, 0, + 0, 0, 0, 2, 2, 2, 0, 0, + 10, 10, 11, 0, 0, 2, 2, 2, + 0, 0, 12, 12, 13, 0, 0, 0, + 2, 2, 14, 14, 15, 0, 0, 0, + 2, 16, 16, 0, 17, 0, 18, 18, + 19, 20, 20, 21, 17, 0, 0, 22, + 22, 23 }; static const int deserialize_json_start = 1; -static const int deserialize_json_first_final = 49; +static const int deserialize_json_first_final = 56; static const int deserialize_json_error = 0; static const int deserialize_json_en_main = 1; -#line 108 "hb-buffer-deserialize-json.rl" +#line 111 "hb-buffer-deserialize-json.rl" static hb_bool_t @@ -499,21 +548,19 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer, while (p < pe && ISSPACE (*p)) p++; if (p < pe && *p == (buffer->len ? ',' : '[')) - { *end_ptr = ++p; - } const char *tok = nullptr; int cs; hb_glyph_info_t info = {0}; hb_glyph_position_t pos = {0}; -#line 512 "hb-buffer-deserialize-json.hh" +#line 552 "hb-buffer-deserialize-json.hh" { cs = deserialize_json_start; } -#line 517 "hb-buffer-deserialize-json.hh" +#line 555 "hb-buffer-deserialize-json.hh" { int _slen; int _trans; @@ -541,8 +588,8 @@ _resume: case 1: #line 38 "hb-buffer-deserialize-json.rl" { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); } break; case 5: @@ -561,25 +608,25 @@ _resume: tok = p; } break; - case 15: + case 17: #line 55 "hb-buffer-deserialize-json.rl" { if (unlikely (!buffer->ensure_glyphs ())) return false; } break; - case 21: + case 23: #line 56 "hb-buffer-deserialize-json.rl" { if (unlikely (!buffer->ensure_unicode ())) return false; } break; - case 16: + case 18: #line 58 "hb-buffer-deserialize-json.rl" { /* TODO Unescape \" and \\ if found. */ if (!hb_font_glyph_from_string (font, - tok, p - tok, + tok+1, p - tok - 2, /* Skip "" */ &info.codepoint)) return false; } break; - case 18: + case 20: #line 66 "hb-buffer-deserialize-json.rl" { if (!parse_uint (tok, p, &info.codepoint)) return false; } break; @@ -604,6 +651,10 @@ _resume: { if (!parse_int (tok, p, &pos.y_advance)) return false; } break; case 14: +#line 72 "hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.mask )) return false; } + break; + case 16: #line 51 "hb-buffer-deserialize-json.rl" { tok = p; @@ -611,7 +662,7 @@ _resume: #line 55 "hb-buffer-deserialize-json.rl" { if (unlikely (!buffer->ensure_glyphs ())) return false; } break; - case 20: + case 22: #line 51 "hb-buffer-deserialize-json.rl" { tok = p; @@ -619,12 +670,12 @@ _resume: #line 56 "hb-buffer-deserialize-json.rl" { if (unlikely (!buffer->ensure_unicode ())) return false; } break; - case 17: + case 19: #line 58 "hb-buffer-deserialize-json.rl" { /* TODO Unescape \" and \\ if found. */ if (!hb_font_glyph_from_string (font, - tok, p - tok, + tok+1, p - tok - 2, /* Skip "" */ &info.codepoint)) return false; } @@ -637,7 +688,7 @@ _resume: *end_ptr = p; } break; - case 19: + case 21: #line 66 "hb-buffer-deserialize-json.rl" { if (!parse_uint (tok, p, &info.codepoint)) return false; } #line 43 "hb-buffer-deserialize-json.rl" @@ -709,7 +760,19 @@ _resume: *end_ptr = p; } break; -#line 713 "hb-buffer-deserialize-json.hh" + case 15: +#line 72 "hb-buffer-deserialize-json.rl" + { if (!parse_uint (tok, p, &info.mask )) return false; } +#line 43 "hb-buffer-deserialize-json.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 733 "hb-buffer-deserialize-json.hh" } _again: @@ -721,7 +784,7 @@ _again: _out: {} } -#line 136 "hb-buffer-deserialize-json.rl" +#line 137 "hb-buffer-deserialize-json.rl" *end_ptr = p; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh new file mode 100644 index 00000000000..cf9c281e86e --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-glyphs.hh @@ -0,0 +1,692 @@ + +#line 1 "hb-buffer-deserialize-text-glyphs.rl" +/* + * Copyright © 2013 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH +#define HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH + +#include "hb.hh" + + +#line 33 "hb-buffer-deserialize-text-glyphs.hh" +static const unsigned char _deserialize_text_glyphs_trans_keys[] = { + 0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, + 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, + 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, + 9u, 124u, 9u, 124u, 9u, 124u, 0 +}; + +static const char _deserialize_text_glyphs_key_spans[] = { + 0, 10, 13, 10, 13, 10, 10, 13, + 10, 1, 13, 10, 14, 82, 116, 116, + 116, 116, 116, 116, 116, 116, 116, 116, + 116, 116, 116 +}; + +static const short _deserialize_text_glyphs_index_offsets[] = { + 0, 0, 11, 25, 36, 50, 61, 72, + 86, 97, 99, 113, 124, 139, 222, 339, + 456, 573, 690, 807, 924, 1041, 1158, 1275, + 1392, 1509, 1626 +}; + +static const char _deserialize_text_glyphs_indicies[] = { + 0, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 1, 3, 1, 1, 4, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 1, 6, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 1, 8, 1, 1, + 9, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 1, 11, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 1, 13, 14, + 14, 14, 14, 14, 14, 14, 14, 14, + 1, 15, 1, 1, 16, 17, 17, 17, + 17, 17, 17, 17, 17, 17, 1, 18, + 19, 19, 19, 19, 19, 19, 19, 19, + 19, 1, 20, 1, 21, 1, 1, 22, + 23, 23, 23, 23, 23, 23, 23, 23, + 23, 1, 24, 25, 25, 25, 25, 25, + 25, 25, 25, 25, 1, 20, 1, 1, + 1, 19, 19, 19, 19, 19, 19, 19, + 19, 19, 19, 1, 26, 26, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 26, 1, + 1, 26, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 26, 26, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 26, 1, 28, + 28, 28, 28, 28, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 28, 27, + 27, 29, 27, 27, 27, 27, 27, 27, + 27, 30, 1, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 31, 27, 27, 32, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 33, 1, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 28, 27, 34, 34, 34, 34, + 34, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 34, 26, 26, 35, 26, + 26, 26, 26, 26, 26, 26, 36, 1, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 37, 26, 26, 38, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 39, + 1, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 26, + 26, 26, 26, 26, 26, 26, 26, 40, + 26, 41, 41, 41, 41, 41, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 41, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 42, 1, 43, 43, + 43, 43, 43, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 43, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 44, 1, 41, 41, 41, 41, 41, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 41, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 42, 1, + 46, 46, 46, 46, 46, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 46, + 1, 1, 47, 1, 1, 1, 1, 1, + 1, 1, 1, 48, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 49, 1, 50, 50, 50, + 50, 50, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 50, 1, 1, 51, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 52, 1, 50, 50, 50, 50, 50, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 50, 1, 1, 51, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 52, 1, 46, + 46, 46, 46, 46, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 46, 1, + 1, 47, 1, 1, 1, 1, 1, 1, + 1, 1, 48, 1, 1, 1, 7, 7, + 7, 7, 7, 7, 7, 7, 7, 7, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 49, 1, 53, 53, 53, 53, + 53, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 53, 1, 1, 54, 1, + 1, 1, 1, 1, 1, 1, 55, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 56, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 57, + 1, 58, 58, 58, 58, 58, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 58, 1, 1, 59, 1, 1, 1, 1, + 1, 1, 1, 60, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 61, 1, 58, 58, + 58, 58, 58, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 58, 1, 1, + 59, 1, 1, 1, 1, 1, 1, 1, + 60, 1, 1, 1, 1, 25, 25, 25, + 25, 25, 25, 25, 25, 25, 25, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 61, 1, 53, 53, 53, 53, 53, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 53, 1, 1, 54, 1, 1, + 1, 1, 1, 1, 1, 55, 1, 1, + 1, 1, 62, 62, 62, 62, 62, 62, + 62, 62, 62, 62, 1, 1, 1, 1, + 1, 1, 56, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 57, 1, + 0 +}; + +static const char _deserialize_text_glyphs_trans_targs[] = { + 16, 0, 18, 3, 19, 22, 19, 22, + 5, 20, 21, 20, 21, 23, 26, 8, + 9, 12, 9, 12, 10, 11, 24, 25, + 24, 25, 15, 15, 14, 1, 2, 6, + 7, 13, 15, 1, 2, 6, 7, 13, + 14, 17, 14, 17, 14, 18, 17, 1, + 4, 14, 17, 1, 14, 17, 1, 2, + 7, 14, 17, 1, 2, 14, 26 +}; + +static const char _deserialize_text_glyphs_trans_actions[] = { + 1, 0, 1, 1, 1, 1, 0, 0, + 1, 1, 1, 0, 0, 1, 1, 1, + 1, 1, 0, 0, 2, 1, 1, 1, + 0, 0, 0, 4, 3, 5, 5, 5, + 5, 4, 6, 7, 7, 7, 7, 0, + 6, 8, 8, 0, 0, 0, 9, 10, + 10, 9, 11, 12, 11, 13, 14, 14, + 14, 13, 15, 16, 16, 15, 0 +}; + +static const char _deserialize_text_glyphs_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 3, 6, + 8, 0, 8, 9, 11, 11, 9, 13, + 15, 15, 13 +}; + +static const int deserialize_text_glyphs_start = 14; +static const int deserialize_text_glyphs_first_final = 14; +static const int deserialize_text_glyphs_error = 0; + +static const int deserialize_text_glyphs_en_main = 14; + + +#line 98 "hb-buffer-deserialize-text-glyphs.rl" + + +static hb_bool_t +_hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe; + + /* Ensure we have positions. */ + (void) hb_buffer_get_glyph_positions (buffer, nullptr); + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? '|' : '[')) + *end_ptr = ++p; + + const char *end = strchr ((char *) p, ']'); + if (end) + pe = eof = end; + else + { + end = strrchr ((char *) p, '|'); + if (end) + pe = eof = end; + else + pe = eof = p; + } + + const char *tok = nullptr; + int cs; + hb_glyph_info_t info = {0}; + hb_glyph_position_t pos = {0}; + +#line 346 "hb-buffer-deserialize-text-glyphs.hh" + { + cs = deserialize_text_glyphs_start; + } + +#line 349 "hb-buffer-deserialize-text-glyphs.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _deserialize_text_glyphs_trans_keys + (cs<<1); + _inds = _deserialize_text_glyphs_indicies + _deserialize_text_glyphs_index_offsets[cs]; + + _slen = _deserialize_text_glyphs_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _deserialize_text_glyphs_trans_targs[_trans]; + + if ( _deserialize_text_glyphs_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _deserialize_text_glyphs_trans_actions[_trans] ) { + case 1: +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} + break; + case 7: +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + break; + case 14: +#line 63 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } + break; + case 2: +#line 64 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_offset )) return false; } + break; + case 16: +#line 65 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } + break; + case 10: +#line 66 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } + break; + case 12: +#line 67 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } + break; + case 4: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} + break; + case 6: +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 13: +#line 63 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 15: +#line 65 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 66 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 67 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 8: +#line 68 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.mask )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 5: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} + break; + case 3: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 516 "hb-buffer-deserialize-text-glyphs.hh" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + switch ( _deserialize_text_glyphs_eof_actions[cs] ) { + case 6: +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 13: +#line 63 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 15: +#line 65 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_offset )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 9: +#line 66 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.x_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 11: +#line 67 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_int (tok, p, &pos.y_advance)) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 8: +#line 68 "hb-buffer-deserialize-text-glyphs.rl" + { if (!parse_uint (tok, p, &info.mask )) return false; } +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 3: +#line 38 "hb-buffer-deserialize-text-glyphs.rl" + { + hb_memset (&info, 0, sizeof (info)); + hb_memset (&pos , 0, sizeof (pos )); +} +#line 51 "hb-buffer-deserialize-text-glyphs.rl" + { + tok = p; +} +#line 55 "hb-buffer-deserialize-text-glyphs.rl" + { + /* TODO Unescape delimiters. */ + if (!hb_font_glyph_from_string (font, + tok, p - tok, + &info.codepoint)) + return false; +} +#line 43 "hb-buffer-deserialize-text-glyphs.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 616 "hb-buffer-deserialize-text-glyphs.hh" + } + } + + _out: {} + } + +#line 136 "hb-buffer-deserialize-text-glyphs.rl" + + + if (pe < orig_pe && *pe == ']') + { + pe++; + if (p == pe) + p++; + } + + *end_ptr = p; + + return p == pe; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh new file mode 100644 index 00000000000..f0c94654533 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text-unicode.hh @@ -0,0 +1,332 @@ + +#line 1 "hb-buffer-deserialize-text-unicode.rl" +/* + * Copyright © 2013 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#ifndef HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH +#define HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH + +#include "hb.hh" + + +#line 33 "hb-buffer-deserialize-text-unicode.hh" +static const unsigned char _deserialize_text_unicode_trans_keys[] = { + 0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u, + 9u, 124u, 0 +}; + +static const char _deserialize_text_unicode_key_spans[] = { + 0, 109, 60, 55, 10, 116, 116, 116, + 116 +}; + +static const short _deserialize_text_unicode_index_offsets[] = { + 0, 0, 110, 171, 227, 238, 355, 472, + 589 +}; + +static const char _deserialize_text_unicode_indicies[] = { + 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 2, 1, 3, + 1, 1, 1, 1, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 4, + 4, 4, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 4, + 4, 4, 4, 1, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 4, + 4, 4, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 4, 4, 4, + 4, 4, 4, 1, 5, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 1, 7, + 7, 7, 7, 7, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 7, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 1, 1, 1, 9, 1, 1, 1, 8, + 8, 8, 8, 8, 8, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 8, + 8, 8, 8, 8, 8, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 10, 1, 11, 11, 11, 11, + 11, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 11, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 0, + 1, 12, 12, 12, 12, 12, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 12, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 13, 1, 12, 12, + 12, 12, 12, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 12, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 13, 1, 0 +}; + +static const char _deserialize_text_unicode_trans_targs[] = { + 1, 0, 2, 3, 5, 7, 8, 6, + 5, 4, 1, 6, 6, 1, 8 +}; + +static const char _deserialize_text_unicode_trans_actions[] = { + 0, 0, 1, 0, 2, 2, 2, 3, + 0, 4, 3, 0, 5, 5, 0 +}; + +static const char _deserialize_text_unicode_eof_actions[] = { + 0, 0, 0, 0, 0, 3, 0, 5, + 5 +}; + +static const int deserialize_text_unicode_start = 1; +static const int deserialize_text_unicode_first_final = 5; +static const int deserialize_text_unicode_error = 0; + +static const int deserialize_text_unicode_en_main = 1; + + +#line 79 "hb-buffer-deserialize-text-unicode.rl" + + +static hb_bool_t +_hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer, + const char *buf, + unsigned int buf_len, + const char **end_ptr, + hb_font_t *font) +{ + const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe; + + while (p < pe && ISSPACE (*p)) + p++; + if (p < pe && *p == (buffer->len ? '|' : '<')) + *end_ptr = ++p; + + const char *end = strchr ((char *) p, '>'); + if (end) + pe = eof = end; + else + { + end = strrchr ((char *) p, '|'); + if (end) + pe = eof = end; + else + pe = eof = p; + } + + + const char *tok = nullptr; + int cs; + hb_glyph_info_t info = {0}; + const hb_glyph_position_t pos = {0}; + +#line 194 "hb-buffer-deserialize-text-unicode.hh" + { + cs = deserialize_text_unicode_start; + } + +#line 197 "hb-buffer-deserialize-text-unicode.hh" + { + int _slen; + int _trans; + const unsigned char *_keys; + const char *_inds; + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _deserialize_text_unicode_trans_keys + (cs<<1); + _inds = _deserialize_text_unicode_indicies + _deserialize_text_unicode_index_offsets[cs]; + + _slen = _deserialize_text_unicode_key_spans[cs]; + _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && + (*p) <= _keys[1] ? + (*p) - _keys[0] : _slen ]; + + cs = _deserialize_text_unicode_trans_targs[_trans]; + + if ( _deserialize_text_unicode_trans_actions[_trans] == 0 ) + goto _again; + + switch ( _deserialize_text_unicode_trans_actions[_trans] ) { + case 1: +#line 38 "hb-buffer-deserialize-text-unicode.rl" + { + hb_memset (&info, 0, sizeof (info)); +} + break; + case 2: +#line 51 "hb-buffer-deserialize-text-unicode.rl" + { + tok = p; +} + break; + case 4: +#line 55 "hb-buffer-deserialize-text-unicode.rl" + {if (!parse_hex (tok, p, &info.codepoint )) return false; } + break; + case 3: +#line 55 "hb-buffer-deserialize-text-unicode.rl" + {if (!parse_hex (tok, p, &info.codepoint )) return false; } +#line 42 "hb-buffer-deserialize-text-unicode.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 5: +#line 57 "hb-buffer-deserialize-text-unicode.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 42 "hb-buffer-deserialize-text-unicode.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 256 "hb-buffer-deserialize-text-unicode.hh" + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + switch ( _deserialize_text_unicode_eof_actions[cs] ) { + case 3: +#line 55 "hb-buffer-deserialize-text-unicode.rl" + {if (!parse_hex (tok, p, &info.codepoint )) return false; } +#line 42 "hb-buffer-deserialize-text-unicode.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; + case 5: +#line 57 "hb-buffer-deserialize-text-unicode.rl" + { if (!parse_uint (tok, p, &info.cluster )) return false; } +#line 42 "hb-buffer-deserialize-text-unicode.rl" + { + buffer->add_info (info); + if (unlikely (!buffer->successful)) + return false; + if (buffer->have_positions) + buffer->pos[buffer->len - 1] = pos; + *end_ptr = p; +} + break; +#line 289 "hb-buffer-deserialize-text-unicode.hh" + } + } + + _out: {} + } + +#line 115 "hb-buffer-deserialize-text-unicode.rl" + + + if (pe < orig_pe && *pe == '>') + { + pe++; + if (p == pe) + p++; + } + + *end_ptr = p; + + return p == pe; +} + +#endif /* HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text.hh deleted file mode 100644 index d34d5a41a4a..00000000000 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-deserialize-text.hh +++ /dev/null @@ -1,853 +0,0 @@ - -#line 1 "hb-buffer-deserialize-text.rl" -/* - * Copyright © 2013 Google, Inc. - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH -#define HB_BUFFER_DESERIALIZE_TEXT_HH - -#include "hb.hh" - - -#line 36 "hb-buffer-deserialize-text.hh" -static const unsigned char _deserialize_text_trans_keys[] = { - 0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u, - 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, - 43u, 124u, 45u, 57u, 48u, 57u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u, 9u, 124u, - 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, - 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 0 -}; - -static const char _deserialize_text_key_spans[] = { - 0, 83, 1, 1, 55, 77, 10, 13, - 10, 10, 13, 10, 1, 13, 10, 14, - 82, 13, 10, 116, 116, 0, 77, 116, - 116, 116, 116, 116, 116, 116, 116, 116, - 116, 116, 116, 116, 116 -}; - -static const short _deserialize_text_index_offsets[] = { - 0, 0, 84, 86, 88, 144, 222, 233, - 247, 258, 269, 283, 294, 296, 310, 321, - 336, 419, 433, 444, 561, 678, 679, 757, - 874, 991, 1108, 1225, 1342, 1459, 1576, 1693, - 1810, 1927, 2044, 2161, 2278 -}; - -static const char _deserialize_text_indicies[] = { - 0, 0, 0, 0, 0, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 1, 4, 1, 5, - 1, 6, 6, 6, 6, 6, 6, 6, - 6, 6, 6, 1, 1, 1, 1, 1, - 1, 1, 6, 6, 6, 6, 6, 6, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 6, 6, 6, 6, 6, 6, - 1, 7, 7, 7, 7, 7, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 7, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 4, 1, 8, - 9, 9, 9, 9, 9, 9, 9, 9, - 9, 1, 10, 1, 1, 11, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 1, - 13, 14, 14, 14, 14, 14, 14, 14, - 14, 14, 1, 15, 16, 16, 16, 16, - 16, 16, 16, 16, 16, 1, 17, 1, - 1, 18, 19, 19, 19, 19, 19, 19, - 19, 19, 19, 1, 20, 21, 21, 21, - 21, 21, 21, 21, 21, 21, 1, 22, - 1, 23, 1, 1, 24, 25, 25, 25, - 25, 25, 25, 25, 25, 25, 1, 26, - 27, 27, 27, 27, 27, 27, 27, 27, - 27, 1, 22, 1, 1, 1, 21, 21, - 21, 21, 21, 21, 21, 21, 21, 21, - 1, 28, 28, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 28, 1, 1, 28, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 28, 28, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 28, 1, 29, 1, 1, 30, - 31, 31, 31, 31, 31, 31, 31, 31, - 31, 1, 32, 33, 33, 33, 33, 33, - 33, 33, 33, 33, 1, 34, 34, 34, - 34, 34, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 34, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 35, 35, 35, 35, - 35, 35, 35, 35, 35, 35, 1, 1, - 1, 36, 37, 1, 1, 35, 35, 35, - 35, 35, 35, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 35, 35, 35, - 35, 35, 35, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 38, 1, 39, 39, 39, 39, 39, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 39, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 40, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 41, 1, 1, - 7, 7, 7, 7, 7, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 7, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 4, 1, 42, 42, - 42, 42, 42, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 42, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 43, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 44, 1, 42, 42, 42, 42, 42, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 42, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 45, 45, 45, 45, 45, 45, - 45, 45, 45, 45, 1, 1, 1, 1, - 43, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 44, 1, - 47, 47, 47, 47, 47, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 47, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 48, 1, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 49, 46, 46, 50, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 51, 52, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 53, 46, 54, 54, 54, - 54, 54, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 54, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 55, - 1, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, - 28, 56, 28, 28, 57, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, - 58, 59, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, - 28, 28, 28, 28, 28, 28, 28, 28, - 60, 28, 61, 61, 61, 61, 61, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 61, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 62, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 63, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 64, 1, 65, - 65, 65, 65, 65, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 65, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 40, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 66, 1, 67, 67, 67, 67, - 67, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 67, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 48, 1, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 49, 46, 46, 50, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 51, - 52, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 46, - 46, 46, 46, 46, 46, 46, 46, 53, - 46, 68, 68, 68, 68, 68, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 68, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 69, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 70, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 43, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 71, 1, 72, 72, - 72, 72, 72, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 72, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 73, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 74, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 75, 1, 72, 72, 72, 72, 72, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 72, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 73, 1, 1, - 1, 1, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 74, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 75, 1, - 68, 68, 68, 68, 68, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 68, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 69, 1, 1, 1, 1, 76, - 76, 76, 76, 76, 76, 76, 76, 76, - 76, 1, 1, 1, 1, 1, 1, 70, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 43, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 71, 1, 77, 77, 77, - 77, 77, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 77, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 78, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 79, 1, 77, 77, 77, 77, 77, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 77, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 33, 33, 33, 33, 33, 33, 33, - 33, 33, 33, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 78, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 79, 1, 61, - 61, 61, 61, 61, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 61, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 62, 1, 1, 1, 14, 14, - 14, 14, 14, 14, 14, 14, 14, 14, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 63, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 64, 1, 0 -}; - -static const char _deserialize_text_trans_targs[] = { - 1, 0, 2, 25, 3, 4, 19, 5, - 23, 24, 8, 27, 36, 27, 36, 30, - 33, 11, 12, 15, 12, 15, 13, 14, - 31, 32, 31, 32, 26, 18, 34, 35, - 34, 35, 20, 19, 6, 21, 22, 20, - 21, 22, 20, 21, 22, 24, 26, 26, - 7, 9, 10, 16, 21, 29, 26, 7, - 9, 10, 16, 21, 29, 28, 17, 21, - 29, 28, 29, 29, 28, 7, 10, 29, - 28, 7, 21, 29, 33, 28, 21, 29 -}; - -static const char _deserialize_text_trans_actions[] = { - 0, 0, 0, 0, 1, 0, 2, 0, - 2, 2, 3, 4, 4, 5, 5, 4, - 4, 3, 3, 3, 0, 0, 6, 3, - 4, 4, 5, 5, 5, 3, 4, 4, - 5, 5, 7, 8, 9, 7, 7, 0, - 0, 0, 10, 10, 10, 8, 12, 13, - 14, 14, 14, 15, 11, 11, 17, 18, - 18, 18, 0, 16, 16, 19, 20, 19, - 19, 0, 0, 13, 10, 21, 21, 10, - 22, 23, 22, 22, 5, 24, 24, 24 -}; - -static const char _deserialize_text_eof_actions[] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 7, 0, 0, 0, 10, - 10, 11, 16, 19, 0, 11, 10, 22, - 22, 10, 24, 24, 19 -}; - -static const int deserialize_text_start = 1; -static const int deserialize_text_first_final = 19; -static const int deserialize_text_error = 0; - -static const int deserialize_text_en_main = 1; - - -#line 114 "hb-buffer-deserialize-text.rl" - - -static hb_bool_t -_hb_buffer_deserialize_text (hb_buffer_t *buffer, - const char *buf, - unsigned int buf_len, - const char **end_ptr, - hb_font_t *font) -{ - const char *p = buf, *pe = buf + buf_len; - - /* Ensure we have positions. */ - (void) hb_buffer_get_glyph_positions (buffer, nullptr); - - while (p < pe && ISSPACE (*p)) - p++; - - const char *eof = pe, *tok = nullptr; - int cs; - hb_glyph_info_t info = {0}; - hb_glyph_position_t pos = {0}; - -#line 428 "hb-buffer-deserialize-text.hh" - { - cs = deserialize_text_start; - } - -#line 433 "hb-buffer-deserialize-text.hh" - { - int _slen; - int _trans; - const unsigned char *_keys; - const char *_inds; - if ( p == pe ) - goto _test_eof; - if ( cs == 0 ) - goto _out; -_resume: - _keys = _deserialize_text_trans_keys + (cs<<1); - _inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs]; - - _slen = _deserialize_text_key_spans[cs]; - _trans = _inds[ _slen > 0 && _keys[0] <=(*p) && - (*p) <= _keys[1] ? - (*p) - _keys[0] : _slen ]; - - cs = _deserialize_text_trans_targs[_trans]; - - if ( _deserialize_text_trans_actions[_trans] == 0 ) - goto _again; - - switch ( _deserialize_text_trans_actions[_trans] ) { - case 1: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} - break; - case 3: -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} - break; - case 5: -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 8: -#line 56 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_unicode ())) return false; } - break; - case 18: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} - break; - case 9: -#line 66 "hb-buffer-deserialize-text.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } - break; - case 21: -#line 68 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } - break; - case 6: -#line 69 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_offset )) return false; } - break; - case 23: -#line 70 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } - break; - case 20: -#line 71 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } - break; - case 15: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} - break; - case 4: -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 2: -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 56 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_unicode ())) return false; } - break; - case 16: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 7: -#line 66 "hb-buffer-deserialize-text.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 10: -#line 68 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 22: -#line 70 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 19: -#line 71 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 24: -#line 72 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 12: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } - break; - case 14: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} - break; - case 17: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 11: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 13: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 55 "hb-buffer-deserialize-text.rl" - { if (unlikely (!buffer->ensure_glyphs ())) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; -#line 722 "hb-buffer-deserialize-text.hh" - } - -_again: - if ( cs == 0 ) - goto _out; - if ( ++p != pe ) - goto _resume; - _test_eof: {} - if ( p == eof ) - { - switch ( _deserialize_text_eof_actions[cs] ) { - case 16: -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 7: -#line 66 "hb-buffer-deserialize-text.rl" - {if (!parse_hex (tok, p, &info.codepoint )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 10: -#line 68 "hb-buffer-deserialize-text.rl" - { if (!parse_uint (tok, p, &info.cluster )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 22: -#line 70 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_offset )) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 19: -#line 71 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.x_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 24: -#line 72 "hb-buffer-deserialize-text.rl" - { if (!parse_int (tok, p, &pos.y_advance)) return false; } -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; - case 11: -#line 38 "hb-buffer-deserialize-text.rl" - { - memset (&info, 0, sizeof (info)); - memset (&pos , 0, sizeof (pos )); -} -#line 51 "hb-buffer-deserialize-text.rl" - { - tok = p; -} -#line 58 "hb-buffer-deserialize-text.rl" - { - /* TODO Unescape delimiters. */ - if (!hb_font_glyph_from_string (font, - tok, p - tok, - &info.codepoint)) - return false; -} -#line 43 "hb-buffer-deserialize-text.rl" - { - buffer->add_info (info); - if (unlikely (!buffer->successful)) - return false; - buffer->pos[buffer->len - 1] = pos; - *end_ptr = p; -} - break; -#line 839 "hb-buffer-deserialize-text.hh" - } - } - - _out: {} - } - -#line 138 "hb-buffer-deserialize-text.rl" - - - *end_ptr = p; - - return p == pe && *(p-1) != ']'; -} - -#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc index 4797d6a79fb..bb2cddcb655 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-serialize.cc @@ -56,7 +56,7 @@ hb_buffer_serialize_list_formats () /** * hb_buffer_serialize_format_from_string: * @str: (array length=len) (element-type uint8_t): a string to parse - * @len: length of @str, or -1 if string is %NULL terminated + * @len: length of @str, or -1 if string is `NULL` terminated * * Parses a string into an #hb_buffer_serialize_format_t. Does not check if * @str is a valid buffer serialization format, use @@ -78,11 +78,11 @@ hb_buffer_serialize_format_from_string (const char *str, int len) * hb_buffer_serialize_format_to_string: * @format: an #hb_buffer_serialize_format_t to convert. * - * Converts @format to the string corresponding it, or %NULL if it is not a valid + * Converts @format to the string corresponding it, or `NULL` if it is not a valid * #hb_buffer_serialize_format_t. * * Return value: (transfer none): - * A %NULL terminated string corresponding to @format. Should not be freed. + * A `NULL` terminated string corresponding to @format. Should not be freed. * * Since: 0.9.7 **/ @@ -183,7 +183,7 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -241,7 +241,7 @@ _hb_buffer_serialize_unicode_json (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -329,7 +329,7 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -381,7 +381,7 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, unsigned int l = p - b; if (buf_size > l) { - memcpy (buf, b, l); + hb_memcpy (buf, b, l); buf += l; buf_size -= l; *buf_consumed += l; @@ -400,9 +400,9 @@ _hb_buffer_serialize_unicode_text (hb_buffer_t *buffer, * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to * write serialized buffer into. * @buf_size: the size of @buf. - * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf. + * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf. * @font: (nullable): the #hb_font_t used to shape this buffer, needed to - * read glyph names and extents. If %NULL, an empty font will be used. + * read glyph names and extents. If `NULL`, an empty font will be used. * @format: the #hb_buffer_serialize_format_t to use for formatting the output. * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties * to serialize. @@ -514,7 +514,7 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to * write serialized buffer into. * @buf_size: the size of @buf. - * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf. + * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf. * @format: the #hb_buffer_serialize_format_t to use for formatting the output. * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties * to serialize. @@ -637,9 +637,9 @@ _hb_buffer_serialize_invalid (hb_buffer_t *buffer, * @buf: (out) (array length=buf_size) (element-type uint8_t): output string to * write serialized buffer into. * @buf_size: the size of @buf. - * @buf_consumed: (out) (optional): if not %NULL, will be set to the number of bytes written into @buf. + * @buf_consumed: (out) (optional): if not `NULL`, will be set to the number of bytes written into @buf. * @font: (nullable): the #hb_font_t used to shape this buffer, needed to - * read glyph names and extents. If %NULL, an empty font will be used. + * read glyph names and extents. If `NULL`, an empty font will be used. * @format: the #hb_buffer_serialize_format_t to use for formatting the output. * @flags: the #hb_buffer_serialize_flags_t that control what glyph properties * to serialize. @@ -721,13 +721,14 @@ parse_hex (const char *pp, const char *end, uint32_t *pv) } #include "hb-buffer-deserialize-json.hh" -#include "hb-buffer-deserialize-text.hh" +#include "hb-buffer-deserialize-text-glyphs.hh" +#include "hb-buffer-deserialize-text-unicode.hh" /** * hb_buffer_deserialize_glyphs: * @buffer: an #hb_buffer_t buffer. * @buf: (array length=buf_len): string to deserialize - * @buf_len: the size of @buf, or -1 if it is %NULL-terminated + * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated * @end_ptr: (out) (optional): output pointer to the character after last * consumed one. * @font: (nullable): font for getting glyph IDs @@ -736,7 +737,8 @@ parse_hex (const char *pp, const char *end, uint32_t *pv) * Deserializes glyphs @buffer from textual representation in the format * produced by hb_buffer_serialize_glyphs(). * - * Return value: %true if @buf is not fully consumed, %false otherwise. + * Return value: `true` if parse was successful, `false` if an error + * occurred. * * Since: 0.9.7 **/ @@ -779,9 +781,9 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, switch (format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: - return _hb_buffer_deserialize_text (buffer, - buf, buf_len, end_ptr, - font); + return _hb_buffer_deserialize_text_glyphs (buffer, + buf, buf_len, end_ptr, + font); case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_deserialize_json (buffer, @@ -800,7 +802,7 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, * hb_buffer_deserialize_unicode: * @buffer: an #hb_buffer_t buffer. * @buf: (array length=buf_len): string to deserialize - * @buf_len: the size of @buf, or -1 if it is %NULL-terminated + * @buf_len: the size of @buf, or -1 if it is `NULL`-terminated * @end_ptr: (out) (optional): output pointer to the character after last * consumed one. * @format: the #hb_buffer_serialize_format_t of the input @buf @@ -808,7 +810,8 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, * Deserializes Unicode @buffer from textual representation in the format * produced by hb_buffer_serialize_unicode(). * - * Return value: %true if @buf is not fully consumed, %false otherwise. + * Return value: `true` if parse was successful, `false` if an error + * occurred. * * Since: 2.7.3 **/ @@ -849,9 +852,9 @@ hb_buffer_deserialize_unicode (hb_buffer_t *buffer, switch (format) { case HB_BUFFER_SERIALIZE_FORMAT_TEXT: - return _hb_buffer_deserialize_text (buffer, - buf, buf_len, end_ptr, - font); + return _hb_buffer_deserialize_text_unicode (buffer, + buf, buf_len, end_ptr, + font); case HB_BUFFER_SERIALIZE_FORMAT_JSON: return _hb_buffer_deserialize_json (buffer, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc index 1b96fafb0d4..f2fef3137e5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer-verify.cc @@ -150,7 +150,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, assert (text_start < text_end); if (0) - printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end); hb_buffer_clear_contents (fragment); @@ -186,7 +186,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t *buffer, bool ret = true; hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); - if (diff) + if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) { buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed."); ret = false; @@ -292,7 +292,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, assert (text_start < text_end); if (0) - printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end); #if 0 hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); @@ -313,7 +313,6 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, bool ret = true; hb_buffer_diff_flags_t diff; - /* * Shape the two fragment streams. */ @@ -382,7 +381,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, * Diff results. */ diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); - if (diff) + if (diff & ~HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH) { buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed."); ret = false; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc index e743e18125a..3532917631d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.cc @@ -51,7 +51,7 @@ * Checks the equality of two #hb_segment_properties_t's. * * Return value: - * %true if all properties of @a equal those of @b, %false otherwise. + * `true` if all properties of @a equal those of @b, `false` otherwise. * * Since: 0.9.7 **/ @@ -172,12 +172,13 @@ hb_buffer_t::enlarge (unsigned int size) while (size >= new_allocated) new_allocated += (new_allocated >> 1) + 32; - static_assert ((sizeof (info[0]) == sizeof (pos[0])), ""); - if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0])))) + unsigned new_bytes; + if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]), &new_bytes))) goto done; - new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_allocated * sizeof (pos[0])); - new_info = (hb_glyph_info_t *) hb_realloc (info, new_allocated * sizeof (info[0])); + static_assert (sizeof (info[0]) == sizeof (pos[0]), ""); + new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_bytes); + new_info = (hb_glyph_info_t *) hb_realloc (info, new_bytes); done: if (unlikely (!new_pos || !new_info)) @@ -208,7 +209,7 @@ hb_buffer_t::make_room_for (unsigned int num_in, assert (have_output); out_info = (hb_glyph_info_t *) pos; - memcpy (out_info, info, out_len * sizeof (out_info[0])); + hb_memcpy (out_info, info, out_len * sizeof (out_info[0])); } return true; @@ -229,7 +230,7 @@ hb_buffer_t::shift_forward (unsigned int count) * Ideally, we should at least set Default_Ignorable bits on * these, as well as consistent cluster values. But the former * is layering violation... */ - memset (info + len, 0, (idx + count - len) * sizeof (info[0])); + hb_memset (info + len, 0, (idx + count - len) * sizeof (info[0])); } len += count; idx += count; @@ -298,8 +299,8 @@ hb_buffer_t::clear () out_len = 0; out_info = info; - memset (context, 0, sizeof context); - memset (context_len, 0, sizeof context_len); + hb_memset (context, 0, sizeof context); + hb_memset (context_len, 0, sizeof context_len); deallocate_var_all (); serial = 0; @@ -313,15 +314,14 @@ hb_buffer_t::enter () serial = 0; shaping_failed = false; scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; - if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR))) + unsigned mul; + if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR, &mul))) { - max_len = hb_max (len * HB_BUFFER_MAX_LEN_FACTOR, - (unsigned) HB_BUFFER_MAX_LEN_MIN); + max_len = hb_max (mul, (unsigned) HB_BUFFER_MAX_LEN_MIN); } - if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR))) + if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR, &mul))) { - max_ops = hb_max (len * HB_BUFFER_MAX_OPS_FACTOR, - (unsigned) HB_BUFFER_MAX_OPS_MIN); + max_ops = hb_max (mul, (unsigned) HB_BUFFER_MAX_OPS_MIN); } } void @@ -345,7 +345,7 @@ hb_buffer_t::add (hb_codepoint_t codepoint, glyph = &info[len]; - memset (glyph, 0, sizeof (*glyph)); + hb_memset (glyph, 0, sizeof (*glyph)); glyph->codepoint = codepoint; glyph->mask = 0; glyph->cluster = cluster; @@ -387,9 +387,11 @@ hb_buffer_t::clear_positions () hb_memset (pos, 0, sizeof (pos[0]) * len); } -void +bool hb_buffer_t::sync () { + bool ret = false; + assert (have_output); assert (idx <= len); @@ -403,12 +405,39 @@ hb_buffer_t::sync () info = out_info; } len = out_len; + ret = true; reset: have_output = false; out_len = 0; out_info = info; idx = 0; + + return ret; +} + +int +hb_buffer_t::sync_so_far () +{ + bool had_output = have_output; + unsigned out_i = out_len; + unsigned i = idx; + unsigned old_idx = idx; + + if (sync ()) + idx = out_i; + else + idx = i; + + if (had_output) + { + have_output = true; + out_len = idx; + } + + assert (idx <= len); + + return idx - old_idx; } bool @@ -493,15 +522,17 @@ hb_buffer_t::merge_clusters_impl (unsigned int start, cluster = hb_min (cluster, info[i].cluster); /* Extend end */ - while (end < len && info[end - 1].cluster == info[end].cluster) - end++; + if (cluster != info[end - 1].cluster) + while (end < len && info[end - 1].cluster == info[end].cluster) + end++; /* Extend start */ - while (idx < start && info[start - 1].cluster == info[start].cluster) - start--; + if (cluster != info[start].cluster) + while (idx < start && info[start - 1].cluster == info[start].cluster) + start--; /* If we hit the start of buffer, continue in out-buffer. */ - if (idx == start) + if (idx == start && info[start].cluster != cluster) for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--) set_cluster (out_info[i - 1], cluster); @@ -576,6 +607,53 @@ hb_buffer_t::delete_glyph () skip_glyph (); } +void +hb_buffer_t::delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info)) +{ + /* Merge clusters and delete filtered glyphs. + * NOTE! We can't use out-buffer as we have positioning data. */ + unsigned int j = 0; + unsigned int count = len; + for (unsigned int i = 0; i < count; i++) + { + if (filter (&info[i])) + { + /* Merge clusters. + * Same logic as delete_glyph(), but for in-place removal. */ + + unsigned int cluster = info[i].cluster; + if (i + 1 < count && cluster == info[i + 1].cluster) + continue; /* Cluster survives; do nothing. */ + + if (j) + { + /* Merge cluster backward. */ + if (cluster < info[j - 1].cluster) + { + unsigned int mask = info[i].mask; + unsigned int old_cluster = info[j - 1].cluster; + for (unsigned k = j; k && info[k - 1].cluster == old_cluster; k--) + set_cluster (info[k - 1], cluster, mask); + } + continue; + } + + if (i + 1 < count) + merge_clusters (i, i + 2); /* Merge cluster forward. */ + + continue; + } + + if (j != i) + { + info[j] = info[i]; + pos[j] = pos[i]; + } + j++; + } + len = j; +} + void hb_buffer_t::guess_segment_properties () { @@ -643,9 +721,9 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) = * Return value: (transfer full): * A newly allocated #hb_buffer_t with a reference count of 1. The initial * reference count should be released with hb_buffer_destroy() when you are done - * using the #hb_buffer_t. This function never returns %NULL. If memory cannot + * using the #hb_buffer_t. This function never returns `NULL`. If memory cannot * be allocated, a special #hb_buffer_t object will be returned on which - * hb_buffer_allocation_successful() returns %false. + * hb_buffer_allocation_successful() returns `false`. * * Since: 0.9.2 **/ @@ -775,7 +853,7 @@ hb_buffer_destroy (hb_buffer_t *buffer) * * Attaches a user-data key/data pair to the specified buffer. * - * Return value: %true if success, %false otherwise + * Return value: `true` if success, `false` otherwise * * Since: 0.9.2 **/ @@ -802,7 +880,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer, * Since: 0.9.2 **/ void * -hb_buffer_get_user_data (hb_buffer_t *buffer, +hb_buffer_get_user_data (const hb_buffer_t *buffer, hb_user_data_key_t *key) { return hb_object_get_user_data (buffer, key); @@ -817,6 +895,32 @@ hb_buffer_get_user_data (hb_buffer_t *buffer, * Sets the type of @buffer contents. Buffers are either empty, contain * characters (before shaping), or contain glyphs (the result of shaping). * + * You rarely need to call this function, since a number of other + * functions transition the content type for you. Namely: + * + * - A newly created buffer starts with content type + * %HB_BUFFER_CONTENT_TYPE_INVALID. Calling hb_buffer_reset(), + * hb_buffer_clear_contents(), as well as calling hb_buffer_set_length() + * with an argument of zero all set the buffer content type to invalid + * as well. + * + * - Calling hb_buffer_add_utf8(), hb_buffer_add_utf16(), + * hb_buffer_add_utf32(), hb_buffer_add_codepoints() and + * hb_buffer_add_latin1() expect that buffer is either empty and + * have a content type of invalid, or that buffer content type is + * %HB_BUFFER_CONTENT_TYPE_UNICODE, and they also set the content + * type to Unicode if they added anything to an empty buffer. + * + * - Finally hb_shape() and hb_shape_full() expect that the buffer + * is either empty and have content type of invalid, or that buffer + * content type is %HB_BUFFER_CONTENT_TYPE_UNICODE, and upon + * success they set the buffer content type to + * %HB_BUFFER_CONTENT_TYPE_GLYPHS. + * + * The above transitions are designed such that one can use a buffer + * in a loop of "reset : add-text : shape" without needing to ever + * modify the content type manually. + * * Since: 0.9.5 **/ void @@ -904,7 +1008,6 @@ hb_buffer_get_unicode_funcs (const hb_buffer_t *buffer) void hb_buffer_set_direction (hb_buffer_t *buffer, hb_direction_t direction) - { if (unlikely (hb_object_is_immutable (buffer))) return; @@ -1278,7 +1381,7 @@ hb_buffer_clear_contents (hb_buffer_t *buffer) * Pre allocates memory for @buffer to fit at least @size number of items. * * Return value: - * %true if @buffer memory allocation succeeded, %false otherwise + * `true` if @buffer memory allocation succeeded, `false` otherwise * * Since: 0.9.2 **/ @@ -1295,7 +1398,7 @@ hb_buffer_pre_allocate (hb_buffer_t *buffer, unsigned int size) * Check if allocating memory for the buffer succeeded. * * Return value: - * %true if @buffer memory allocation succeeded, %false otherwise. + * `true` if @buffer memory allocation succeeded, `false` otherwise. * * Since: 0.9.2 **/ @@ -1340,7 +1443,7 @@ hb_buffer_add (hb_buffer_t *buffer, * end. * * Return value: - * %true if @buffer memory allocation succeeded, %false otherwise. + * `true` if @buffer memory allocation succeeded, `false` otherwise. * * Since: 0.9.2 **/ @@ -1356,9 +1459,9 @@ hb_buffer_set_length (hb_buffer_t *buffer, /* Wipe the new space */ if (length > buffer->len) { - memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); + hb_memset (buffer->info + buffer->len, 0, sizeof (buffer->info[0]) * (length - buffer->len)); if (buffer->have_positions) - memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); + hb_memset (buffer->pos + buffer->len, 0, sizeof (buffer->pos[0]) * (length - buffer->len)); } buffer->len = length; @@ -1426,7 +1529,7 @@ hb_buffer_get_glyph_infos (hb_buffer_t *buffer, * If buffer did not have positions before, the positions will be * initialized to zeros, unless this function is called from * within a buffer message callback (see hb_buffer_set_message_func()), - * in which case %NULL is returned. + * in which case `NULL` is returned. * * Return value: (transfer none) (array length=length): * The @buffer glyph position array. @@ -1461,7 +1564,7 @@ hb_buffer_get_glyph_positions (hb_buffer_t *buffer, * and cleared of position data when hb_buffer_clear_contents() is called. * * Return value: - * %true if the @buffer has position array, %false otherwise. + * `true` if the @buffer has position array, `false` otherwise. * * Since: 2.7.3 **/ @@ -1645,10 +1748,10 @@ hb_buffer_add_utf (hb_buffer_t *buffer, * @buffer: An #hb_buffer_t * @text: (array length=text_length) (element-type uint8_t): An array of UTF-8 * characters to append. - * @text_length: The length of the @text, or -1 if it is %NULL terminated. + * @text_length: The length of the @text, or -1 if it is `NULL` terminated. * @item_offset: The offset of the first character to add to the @buffer. * @item_length: The number of characters to add to the @buffer, or -1 for the - * end of @text (assuming it is %NULL terminated). + * end of @text (assuming it is `NULL` terminated). * * See hb_buffer_add_codepoints(). * @@ -1671,10 +1774,10 @@ hb_buffer_add_utf8 (hb_buffer_t *buffer, * hb_buffer_add_utf16: * @buffer: An #hb_buffer_t * @text: (array length=text_length): An array of UTF-16 characters to append - * @text_length: The length of the @text, or -1 if it is %NULL terminated + * @text_length: The length of the @text, or -1 if it is `NULL` terminated * @item_offset: The offset of the first character to add to the @buffer * @item_length: The number of characters to add to the @buffer, or -1 for the - * end of @text (assuming it is %NULL terminated) + * end of @text (assuming it is `NULL` terminated) * * See hb_buffer_add_codepoints(). * @@ -1697,10 +1800,10 @@ hb_buffer_add_utf16 (hb_buffer_t *buffer, * hb_buffer_add_utf32: * @buffer: An #hb_buffer_t * @text: (array length=text_length): An array of UTF-32 characters to append - * @text_length: The length of the @text, or -1 if it is %NULL terminated + * @text_length: The length of the @text, or -1 if it is `NULL` terminated * @item_offset: The offset of the first character to add to the @buffer * @item_length: The number of characters to add to the @buffer, or -1 for the - * end of @text (assuming it is %NULL terminated) + * end of @text (assuming it is `NULL` terminated) * * See hb_buffer_add_codepoints(). * @@ -1724,10 +1827,10 @@ hb_buffer_add_utf32 (hb_buffer_t *buffer, * @buffer: An #hb_buffer_t * @text: (array length=text_length) (element-type uint8_t): an array of UTF-8 * characters to append - * @text_length: the length of the @text, or -1 if it is %NULL terminated + * @text_length: the length of the @text, or -1 if it is `NULL` terminated * @item_offset: the offset of the first character to add to the @buffer * @item_length: the number of characters to add to the @buffer, or -1 for the - * end of @text (assuming it is %NULL terminated) + * end of @text (assuming it is `NULL` terminated) * * Similar to hb_buffer_add_codepoints(), but allows only access to first 256 * Unicode code points that can fit in 8-bit strings. @@ -1750,10 +1853,10 @@ hb_buffer_add_latin1 (hb_buffer_t *buffer, * hb_buffer_add_codepoints: * @buffer: a #hb_buffer_t to append characters to. * @text: (array length=text_length): an array of Unicode code points to append. - * @text_length: the length of the @text, or -1 if it is %NULL terminated. + * @text_length: the length of the @text, or -1 if it is `NULL` terminated. * @item_offset: the offset of the first code point to add to the @buffer. * @item_length: the number of code points to add to the @buffer, or -1 for the - * end of @text (assuming it is %NULL terminated). + * end of @text (assuming it is `NULL` terminated). * * Appends characters from @text array to @buffer. The @item_offset is the * position of the first character from @text that will be appended, and @@ -1766,7 +1869,9 @@ hb_buffer_add_latin1 (hb_buffer_t *buffer, * marks at stat of run. * * This function does not check the validity of @text, it is up to the caller - * to ensure it contains a valid Unicode code points. + * to ensure it contains a valid Unicode scalar values. In contrast, + * hb_buffer_add_utf32() can be used that takes similar input but performs + * sanity-check on the input. * * Since: 0.9.31 **/ @@ -1829,9 +1934,9 @@ hb_buffer_append (hb_buffer_t *buffer, hb_segment_properties_overlay (&buffer->props, &source->props); - memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); + hb_memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); if (buffer->have_positions) - memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); + hb_memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) { @@ -2019,7 +2124,7 @@ hb_buffer_diff (hb_buffer_t *buffer, result |= HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH; if (buf_info->cluster != ref_info->cluster) result |= HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH; - if ((buf_info->mask & ~ref_info->mask & HB_GLYPH_FLAG_DEFINED)) + if ((buf_info->mask ^ ref_info->mask) & HB_GLYPH_FLAG_DEFINED) result |= HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH; if (contains && ref_info->codepoint == dottedcircle_glyph) result |= HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT; @@ -2074,6 +2179,13 @@ hb_buffer_set_message_func (hb_buffer_t *buffer, hb_buffer_message_func_t func, void *user_data, hb_destroy_func_t destroy) { + if (unlikely (hb_object_is_immutable (buffer))) + { + if (destroy) + destroy (user_data); + return; + } + if (buffer->message_destroy) buffer->message_destroy (buffer->message_data); @@ -2090,8 +2202,16 @@ hb_buffer_set_message_func (hb_buffer_t *buffer, bool hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap) { + assert (!have_output || (out_info == info && out_len == idx)); + + message_depth++; + char buf[100]; vsnprintf (buf, sizeof (buf), fmt, ap); - return (bool) this->message_func (this, font, buf, this->message_data); + bool ret = (bool) this->message_func (this, font, buf, this->message_data); + + message_depth--; + + return ret; } #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.h b/src/java.desktop/share/native/libharfbuzz/hb-buffer.h index d5c2b25f852..9b21ffb10fa 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.h @@ -142,6 +142,15 @@ typedef struct hb_glyph_info_t { * shaping, otherwise the buffer flag will not be * reliably produced. * Since: 4.0.0 + * @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL: In scripts that use elongation (Arabic, + Mongolian, Syriac, etc.), this flag signifies + that it is safe to insert a U+0640 TATWEEL + character before this cluster for elongation. + This flag does not determine the + script-specific elongation places, but only + when it is safe to do the elongation without + interrupting text shaping. + Since: 5.1.0 * @HB_GLYPH_FLAG_DEFINED: All the currently defined flags. * * Flags for #hb_glyph_info_t. @@ -149,10 +158,11 @@ typedef struct hb_glyph_info_t { * Since: 1.5.0 */ typedef enum { /*< flags >*/ - HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001, - HB_GLYPH_FLAG_UNSAFE_TO_CONCAT = 0x00000002, + HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001, + HB_GLYPH_FLAG_UNSAFE_TO_CONCAT = 0x00000002, + HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL = 0x00000004, - HB_GLYPH_FLAG_DEFINED = 0x00000003 /* OR of all defined flags */ + HB_GLYPH_FLAG_DEFINED = 0x00000007 /* OR of all defined flags */ } hb_glyph_flags_t; HB_EXTERN hb_glyph_flags_t @@ -266,7 +276,7 @@ hb_buffer_set_user_data (hb_buffer_t *buffer, hb_bool_t replace); HB_EXTERN void * -hb_buffer_get_user_data (hb_buffer_t *buffer, +hb_buffer_get_user_data (const hb_buffer_t *buffer, hb_user_data_key_t *key); @@ -373,6 +383,10 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer); * flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT * glyph-flag should be produced by the shaper. By default * it will not be produced since it incurs a cost. Since: 4.0.0 + * @HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL: + * flag indicating that the @HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL + * glyph-flag should be produced by the shaper. By default + * it will not be produced. Since: 5.1.0 * @HB_BUFFER_FLAG_DEFINED: All currently defined flags: Since: 4.4.0 * * Flags for #hb_buffer_t. @@ -388,8 +402,9 @@ typedef enum { /*< flags >*/ HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u, HB_BUFFER_FLAG_VERIFY = 0x00000020u, HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u, + HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL = 0x00000080u, - HB_BUFFER_FLAG_DEFINED = 0x0000007Fu + HB_BUFFER_FLAG_DEFINED = 0x000000FFu } hb_buffer_flags_t; HB_EXTERN void @@ -748,23 +763,23 @@ hb_buffer_diff (hb_buffer_t *buffer, /* - * Debugging. + * Tracing. */ /** * hb_buffer_message_func_t: * @buffer: An #hb_buffer_t to work upon * @font: The #hb_font_t the @buffer is shaped with - * @message: %NULL-terminated message passed to the function + * @message: `NULL`-terminated message passed to the function * @user_data: User data pointer passed by the caller * * A callback method for #hb_buffer_t. The method gets called with the * #hb_buffer_t it was set on, the #hb_font_t the buffer is shaped with and a * message describing what step of the shaping process will be performed. - * Returning %false from this method will skip this shaping step and move to + * Returning `false` from this method will skip this shaping step and move to * the next one. * - * Return value: %true to perform the shaping step, %false to skip it. + * Return value: `true` to perform the shaping step, `false` to skip it. * * Since: 1.1.3 */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh index 44f30d0a5dc..c1476364de5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-buffer.hh @@ -32,28 +32,9 @@ #include "hb.hh" #include "hb-unicode.hh" +#include "hb-set-digest.hh" -#ifndef HB_BUFFER_MAX_LEN_FACTOR -#define HB_BUFFER_MAX_LEN_FACTOR 64 -#endif -#ifndef HB_BUFFER_MAX_LEN_MIN -#define HB_BUFFER_MAX_LEN_MIN 16384 -#endif -#ifndef HB_BUFFER_MAX_LEN_DEFAULT -#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */ -#endif - -#ifndef HB_BUFFER_MAX_OPS_FACTOR -#define HB_BUFFER_MAX_OPS_FACTOR 1024 -#endif -#ifndef HB_BUFFER_MAX_OPS_MIN -#define HB_BUFFER_MAX_OPS_MIN 16384 -#endif -#ifndef HB_BUFFER_MAX_OPS_DEFAULT -#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */ -#endif - static_assert ((sizeof (hb_glyph_info_t) == 20), ""); static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), ""); @@ -207,6 +188,14 @@ struct hb_buffer_t hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; } hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; } + hb_set_digest_t digest () const + { + hb_set_digest_t d; + d.init (); + d.add_array (&info[0].codepoint, len, sizeof (info[0])); + return d; + } + HB_INTERNAL void similar (const hb_buffer_t &src); HB_INTERNAL void reset (); HB_INTERNAL void clear (); @@ -288,7 +277,8 @@ struct hb_buffer_t HB_INTERNAL void guess_segment_properties (); - HB_INTERNAL void sync (); + HB_INTERNAL bool sync (); + HB_INTERNAL int sync_so_far (); HB_INTERNAL void clear_output (); HB_INTERNAL void clear_positions (); @@ -401,6 +391,8 @@ struct hb_buffer_t HB_INTERNAL void merge_out_clusters (unsigned int start, unsigned int end); /* Merge clusters for deleting current glyph, and skip it. */ HB_INTERNAL void delete_glyph (); + HB_INTERNAL void delete_glyphs_inplace (bool (*filter) (const hb_glyph_info_t *info)); + /* Adds glyph flags in mask to infos with clusters between start and end. @@ -461,6 +453,17 @@ struct hb_buffer_t start, end, true); } + void safe_to_insert_tatweel (unsigned int start = 0, unsigned int end = -1) + { + if ((flags & HB_BUFFER_FLAG_PRODUCE_SAFE_TO_INSERT_TATWEEL) == 0) + { + unsafe_to_break (start, end); + return; + } + _set_glyph_flags (HB_GLYPH_FLAG_SAFE_TO_INSERT_TATWEEL, + start, end, + true); + } void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1) { if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)) @@ -555,15 +558,11 @@ struct hb_buffer_t if (likely (!messaging ())) return true; - message_depth++; - va_list ap; va_start (ap, fmt); bool ret = message_impl (font, fmt, ap); va_end (ap); - message_depth--; - return ret; #endif } @@ -582,21 +581,59 @@ struct hb_buffer_t unsigned int cluster, hb_mask_t mask) { - for (unsigned int i = start; i < end; i++) - if (cluster != infos[i].cluster) + if (unlikely (start == end)) + return; + + unsigned cluster_first = infos[start].cluster; + unsigned cluster_last = infos[end - 1].cluster; + + if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS || + (cluster != cluster_first && cluster != cluster_last)) + { + for (unsigned int i = start; i < end; i++) + if (cluster != infos[i].cluster) + { + scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; + infos[i].mask |= mask; + } + return; + } + + /* Monotone clusters */ + + if (cluster == cluster_first) + { + for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--) + { + scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; + infos[i - 1].mask |= mask; + } + } + else /* cluster == cluster_last */ + { + for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++) { scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; infos[i].mask |= mask; } + } } - static unsigned + unsigned _infos_find_min_cluster (const hb_glyph_info_t *infos, unsigned start, unsigned end, unsigned cluster = UINT_MAX) { - for (unsigned int i = start; i < end; i++) - cluster = hb_min (cluster, infos[i].cluster); - return cluster; + if (unlikely (start == end)) + return cluster; + + if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS) + { + for (unsigned int i = start; i < end; i++) + cluster = hb_min (cluster, infos[i].cluster); + return cluster; + } + + return hb_min (cluster, hb_min (infos[start].cluster, infos[end - 1].cluster)); } void clear_glyph_flags (hb_mask_t mask = 0) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cache.hh b/src/java.desktop/share/native/libharfbuzz/hb-cache.hh index de8a808ec45..eb4a510fbf6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cache.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cache.hh @@ -32,27 +32,39 @@ /* Implements a lockfree cache for int->int functions. */ -template +template struct hb_cache_t { + using item_t = typename std::conditional::type, + typename std::conditional::type + >::type; + static_assert ((key_bits >= cache_bits), ""); - static_assert ((key_bits + value_bits - cache_bits <= 8 * sizeof (hb_atomic_int_t)), ""); - static_assert (sizeof (hb_atomic_int_t) == sizeof (unsigned int), ""); + static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), ""); + + hb_cache_t () { init (); } void init () { clear (); } - void fini () {} void clear () { for (unsigned i = 0; i < ARRAY_LENGTH (values); i++) - values[i].set_relaxed (-1); + values[i] = -1; } bool get (unsigned int key, unsigned int *value) const { unsigned int k = key & ((1u<> value_bits) != (key >> cache_bits)) return false; *value = v & ((1u<>cache_bits)< hb_cmap_cache_t; -typedef hb_cache_t<16, 24, 8> hb_advance_cache_t; - #endif /* HB_CACHE_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh index 2c980c60279..e92e8140fd0 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-common.hh @@ -284,65 +284,56 @@ struct UnsizedByteStr : UnsizedArrayOf /* A byte string associated with the current offset and an error condition */ struct byte_str_ref_t { - byte_str_ref_t () { init (); } - - void init () - { - str = hb_ubytes_t (); - offset = 0; - error = false; - } - - void fini () {} + byte_str_ref_t () + : str () {} byte_str_ref_t (const hb_ubytes_t &str_, unsigned int offset_ = 0) - : str (str_), offset (offset_), error (false) {} + : str (str_) { set_offset (offset_); } void reset (const hb_ubytes_t &str_, unsigned int offset_ = 0) { str = str_; - offset = offset_; - error = false; + set_offset (offset_); } const unsigned char& operator [] (int i) { - if (unlikely ((unsigned int) (offset + i) >= str.length)) + if (unlikely ((unsigned int) (get_offset () + i) >= str.length)) { set_error (); return Null (unsigned char); } - return str[offset + i]; + return str.arrayZ[get_offset () + i]; } + unsigned char head_unchecked () const { return str.arrayZ[get_offset ()]; } + /* Conversion to hb_ubytes_t */ - operator hb_ubytes_t () const { return str.sub_array (offset, str.length - offset); } + operator hb_ubytes_t () const { return str.sub_array (get_offset ()); } hb_ubytes_t sub_array (unsigned int offset_, unsigned int len_) const { return str.sub_array (offset_, len_); } bool avail (unsigned int count=1) const - { return (!in_error () && offset + count <= str.length); } + { return get_offset () + count <= str.length; } void inc (unsigned int count=1) { - if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length))) - { - offset += count; - } - else - { - offset = str.length; - set_error (); - } + /* Automatically puts us in error if count is out-of-range. */ + set_offset (get_offset () + count); } - void set_error () { error = true; } - bool in_error () const { return error; } + /* We (ab)use ubytes backwards_length as a cursor (called offset), + * as well as to store error condition. */ - hb_ubytes_t str; - unsigned int offset; /* beginning of the sub-string within str */ + unsigned get_offset () const { return str.backwards_length; } + void set_offset (unsigned offset) { str.backwards_length = offset; } + + void set_error () { str.backwards_length = str.length + 1; } + bool in_error () const { return str.backwards_length > str.length; } + + unsigned total_size () const { return str.length; } protected: - bool error; + hb_ubytes_t str; }; using byte_str_array_t = hb_vector_t; @@ -491,8 +482,15 @@ struct arg_stack_t : cff_stack_t /* an operator prefixed by its operands in a byte string */ struct op_str_t { - hb_ubytes_t str; - op_code_t op; + /* This used to have a hb_ubytes_t. Using a pointer and length + * in a particular order, saves 8 bytes in this struct and more + * in our parsed_cs_op_t subclass. */ + + const unsigned char *ptr = nullptr; + + op_code_t op = OpCode_Invalid; + + uint8_t length = 0; }; /* base of OP_SERIALIZER */ @@ -503,9 +501,11 @@ struct op_serializer_t { TRACE_SERIALIZE (this); - HBUINT8 *d = c->allocate_size (opstr.str.length); + unsigned char *d = c->allocate_size (opstr.length); if (unlikely (!d)) return_trace (false); - memcpy (d, &opstr.str[0], opstr.str.length); + /* Faster than hb_memcpy for small strings. */ + for (unsigned i = 0; i < opstr.length; i++) + d[i] = opstr.ptr[i]; return_trace (true); } }; @@ -522,23 +522,17 @@ struct parsed_values_t void alloc (unsigned n) { - values.alloc (n); + values.alloc (n, true); } - void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ()) - { - VAL *val = values.push (); - val->op = op; - val->str = str_ref.str.sub_array (opStart, str_ref.offset - opStart); - opStart = str_ref.offset; - } - - void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v) + void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t (), const VAL &v = VAL ()) { VAL *val = values.push (v); val->op = op; - val->str = str_ref.sub_array ( opStart, str_ref.offset - opStart); - opStart = str_ref.offset; + auto arr = str_ref.sub_array (opStart, str_ref.get_offset () - opStart); + val->ptr = arr.arrayZ; + val->length = arr.length; + opStart = str_ref.get_offset (); } bool has_op (op_code_t op) const @@ -549,8 +543,7 @@ struct parsed_values_t } unsigned get_count () const { return values.length; } - const VAL &get_value (unsigned int i) const { return values[i]; } - const VAL &operator [] (unsigned int i) const { return get_value (i); } + const VAL &operator [] (unsigned int i) const { return values[i]; } unsigned int opStart; hb_vector_t values; @@ -565,23 +558,23 @@ struct interp_env_t str_ref.reset (str_); } bool in_error () const - { return error || str_ref.in_error () || argStack.in_error (); } + { return str_ref.in_error () || argStack.in_error (); } - void set_error () { error = true; } + void set_error () { str_ref.set_error (); } op_code_t fetch_op () { op_code_t op = OpCode_Invalid; if (unlikely (!str_ref.avail ())) return OpCode_Invalid; - op = (op_code_t)(unsigned char)str_ref[0]; + op = (op_code_t) str_ref.head_unchecked (); + str_ref.inc (); if (op == OpCode_escape) { if (unlikely (!str_ref.avail ())) return OpCode_Invalid; - op = Make_OpCode_ESC(str_ref[1]); + op = Make_OpCode_ESC (str_ref.head_unchecked ()); str_ref.inc (); } - str_ref.inc (); return op; } @@ -596,8 +589,6 @@ struct interp_env_t str_ref; arg_stack_t argStack; - protected: - bool error = false; }; using num_interp_env_t = interp_env_t<>; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh index f4f41370495..52b52c3f769 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-cs-common.hh @@ -881,7 +881,13 @@ struct cs_interpreter_t : interpreter_t { SUPER::env.set_endchar (false); + unsigned max_ops = HB_CFF_MAX_OPS; for (;;) { + if (unlikely (!--max_ops)) + { + SUPER::env.set_error (); + break; + } OPSET::process_op (SUPER::env.fetch_op (), SUPER::env, param); if (unlikely (SUPER::env.in_error ())) return false; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh index 041585a89a6..0c0cec9986a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff-interp-dict-common.hh @@ -35,10 +35,8 @@ using namespace OT; /* an opstr and the parsed out dict value(s) */ struct dict_val_t : op_str_t { - void init () { single_val.set_int (0); } + void init () {} void fini () {} - - number_t single_val; }; typedef dict_val_t num_dict_val_t; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh index cfcf442ee7d..fbb31c9ee16 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff1-interp-cs.hh @@ -38,7 +38,8 @@ typedef biased_subrs_t cff1_biased_subrs_t; struct cff1_cs_interp_env_t : cs_interp_env_t { template - cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd) + cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd, + const int *coords_=nullptr, unsigned int num_coords_=0) : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs) { processed_width = false; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh b/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh index 791f3aab56a..c970633e064 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cff2-interp-cs.hh @@ -40,20 +40,22 @@ struct blend_arg_t : number_t void set_real (double v) { reset_blends (); number_t::set_real (v); } void set_blends (unsigned int numValues_, unsigned int valueIndex_, - unsigned int numBlends, hb_array_t blends_) + hb_array_t blends_) { numValues = numValues_; valueIndex = valueIndex_; - deltas.resize (numBlends); + unsigned numBlends = blends_.length; + if (unlikely (!deltas.resize_exact (numBlends))) + return; for (unsigned int i = 0; i < numBlends; i++) - deltas[i] = blends_[i]; + deltas.arrayZ[i] = blends_.arrayZ[i]; } bool blending () const { return deltas.length > 0; } void reset_blends () { numValues = valueIndex = 0; - deltas.resize (0); + deltas.shrink (0); } unsigned int numValues; @@ -61,7 +63,6 @@ struct blend_arg_t : number_t hb_vector_t deltas; }; -typedef interp_env_t BlendInterpEnv; typedef biased_subrs_t cff2_biased_subrs_t; template @@ -117,7 +118,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t region_count = varStore->varStore.get_region_index_count (get_ivs ()); if (do_blend) { - if (unlikely (!scalars.resize (region_count))) + if (unlikely (!scalars.resize_exact (region_count))) SUPER::set_error (); else varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords, @@ -154,13 +155,16 @@ struct cff2_cs_interp_env_t : cs_interp_env_t { if (likely (scalars.length == deltas.length)) { - for (unsigned int i = 0; i < scalars.length; i++) - v += (double) scalars[i] * deltas[i].to_real (); + unsigned count = scalars.length; + for (unsigned i = 0; i < count; i++) + v += (double) scalars.arrayZ[i] * deltas.arrayZ[i].to_real (); } } return v; } + bool have_coords () const { return num_coords; } + protected: const int *coords; unsigned int num_coords; @@ -220,7 +224,10 @@ struct cff2_cs_opset_t : cs_opset_t, PAR const hb_array_t blends, unsigned n, unsigned i) { - arg.set_blends (n, i, blends.length, blends); + if (env.have_coords ()) + arg.set_int (round (arg.to_real () + env.blend_deltas (blends))); + else + arg.set_blends (n, i, blends); } template diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.cc b/src/java.desktop/share/native/libharfbuzz/hb-common.cc index 310053e89df..ef862618d11 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-common.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-common.cc @@ -29,32 +29,6 @@ #include "hb.hh" #include "hb-machinery.hh" -#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE)) -#define HB_NO_SETLOCALE 1 -#endif - -#ifndef HB_NO_SETLOCALE - -#include -#ifdef HAVE_XLOCALE_H -#include // Needed on BSD/OS X for uselocale -#endif - -#ifdef WIN32 -#define hb_locale_t _locale_t -#else -#define hb_locale_t locale_t -#endif -#define hb_setlocale setlocale -#define hb_uselocale uselocale - -#else - -#define hb_locale_t void * -#define hb_setlocale(Category, Locale) "C" -#define hb_uselocale(Locale) ((hb_locale_t) 0) - -#endif /** * SECTION:hb-common @@ -99,7 +73,7 @@ _hb_options_init () } /* This is idempotent and threadsafe. */ - _hb_options.set_relaxed (u.i); + _hb_options = u.i; } @@ -108,7 +82,7 @@ _hb_options_init () /** * hb_tag_from_string: * @str: (array length=len) (element-type uint8_t): String to convert - * @len: Length of @str, or -1 if it is %NULL-terminated + * @len: Length of @str, or -1 if it is `NULL`-terminated * * Converts a string into an #hb_tag_t. Valid tags * are four characters. Shorter input strings will be @@ -170,7 +144,7 @@ static const char direction_strings[][4] = { /** * hb_direction_from_string: * @str: (array length=len) (element-type uint8_t): String to convert - * @len: Length of @str, or -1 if it is %NULL-terminated + * @len: Length of @str, or -1 if it is `NULL`-terminated * * Converts a string to an #hb_direction_t. * @@ -285,7 +259,7 @@ struct hb_language_item_t { lang = (hb_language_t) hb_malloc(len); if (likely (lang)) { - memcpy((unsigned char *) lang, s, len); + hb_memcpy((unsigned char *) lang, s, len); for (unsigned char *p = (unsigned char *) lang; *p; p++) *p = canon_map[*p]; } @@ -357,7 +331,7 @@ lang_find_or_insert (const char *key) * hb_language_from_string: * @str: (array length=len) (element-type uint8_t): a string representing * a BCP 47 language tag - * @len: length of the @str, or -1 if it is %NULL-terminated. + * @len: length of the @str, or -1 if it is `NULL`-terminated. * * Converts @str representing a BCP 47 language tag to the corresponding * #hb_language_t. @@ -379,7 +353,7 @@ hb_language_from_string (const char *str, int len) /* NUL-terminate it. */ char strbuf[64]; len = hb_min (len, (int) sizeof (strbuf) - 1); - memcpy (strbuf, str, len); + hb_memcpy (strbuf, str, len); strbuf[len] = '\0'; item = lang_find_or_insert (strbuf); } @@ -396,7 +370,7 @@ hb_language_from_string (const char *str, int len) * Converts an #hb_language_t to a string. * * Return value: (transfer none): - * A %NULL-terminated string representing the @language. Must not be freed by + * A `NULL`-terminated string representing the @language. Must not be freed by * the caller. * * Since: 0.9.2 @@ -441,6 +415,38 @@ hb_language_get_default () return language; } +/** + * hb_language_matches: + * @language: The #hb_language_t to work on + * @specific: Another #hb_language_t + * + * Check whether a second language tag is the same or a more + * specific version of the provided language tag. For example, + * "fa_IR.utf8" is a more specific tag for "fa" or for "fa_IR". + * + * Return value: `true` if languages match, `false` otherwise. + * + * Since: 5.0.0 + **/ +hb_bool_t +hb_language_matches (hb_language_t language, + hb_language_t specific) +{ + if (language == specific) return true; + if (!language || !specific) return false; + + const char *l = language->s; + const char *s = specific->s; + unsigned ll = strlen (l); + unsigned sl = strlen (s); + + if (ll > sl) + return false; + + return strncmp (l, s, ll) == 0 && + (s[ll] == '\0' || s[ll] == '-'); +} + /* hb_script_t */ @@ -498,7 +504,7 @@ hb_script_from_iso15924_tag (hb_tag_t tag) * hb_script_from_string: * @str: (array length=len) (element-type uint8_t): a string representing an * ISO 15924 tag. - * @len: length of the @str, or -1 if it is %NULL-terminated. + * @len: length of the @str, or -1 if it is `NULL`-terminated. * * Converts a string @str representing an ISO 15924 script tag to a * corresponding #hb_script_t. Shorthand for hb_tag_from_string() then @@ -693,8 +699,8 @@ hb_version_string () * Tests the library version against a minimum value, * as three integer components. * - * Return value: %true if the library is equal to or greater than - * the test value, %false otherwise + * Return value: `true` if the library is equal to or greater than + * the test value, `false` otherwise * * Since: 0.9.30 **/ @@ -881,7 +887,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature) /** * hb_feature_from_string: * @str: (array length=len) (element-type uint8_t): a string to parse - * @len: length of @str, or -1 if string is %NULL terminated + * @len: length of @str, or -1 if string is `NULL` terminated * @feature: (out): the #hb_feature_t to initialize with the parsed values * * Parses a string into a #hb_feature_t. @@ -923,7 +929,7 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature) * * * Return value: - * %true if @str is successfully parsed, %false otherwise + * `true` if @str is successfully parsed, `false` otherwise * * Since: 0.9.5 **/ @@ -944,7 +950,7 @@ hb_feature_from_string (const char *str, int len, } if (feature) - memset (feature, 0, sizeof (*feature)); + hb_memset (feature, 0, sizeof (*feature)); return false; } @@ -954,7 +960,7 @@ hb_feature_from_string (const char *str, int len, * @buf: (array length=size) (out): output string * @size: the allocated size of @buf * - * Converts a #hb_feature_t into a %NULL-terminated string in the format + * Converts a #hb_feature_t into a `NULL`-terminated string in the format * understood by hb_feature_from_string(). The client in responsible for * allocating big enough size for @buf, 128 bytes is more than enough. * @@ -993,7 +999,7 @@ hb_feature_to_string (hb_feature_t *feature, } assert (len < ARRAY_LENGTH (s)); len = hb_min (len, size - 1); - memcpy (buf, s, len); + hb_memcpy (buf, s, len); buf[len] = '\0'; } @@ -1022,7 +1028,7 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation /** * hb_variation_from_string: * @str: (array length=len) (element-type uint8_t): a string to parse - * @len: length of @str, or -1 if string is %NULL terminated + * @len: length of @str, or -1 if string is `NULL` terminated * @variation: (out): the #hb_variation_t to initialize with the parsed values * * Parses a string into a #hb_variation_t. @@ -1035,7 +1041,7 @@ parse_one_variation (const char **pp, const char *end, hb_variation_t *variation * number. For example `wght=500`, or `slnt=-7.5`. * * Return value: - * %true if @str is successfully parsed, %false otherwise + * `true` if @str is successfully parsed, `false` otherwise * * Since: 1.4.2 */ @@ -1056,7 +1062,7 @@ hb_variation_from_string (const char *str, int len, } if (variation) - memset (variation, 0, sizeof (*variation)); + hb_memset (variation, 0, sizeof (*variation)); return false; } @@ -1104,10 +1110,10 @@ get_C_locale () /** * hb_variation_to_string: * @variation: an #hb_variation_t to convert - * @buf: (array length=size) (out): output string + * @buf: (array length=size) (out caller-allocates): output string * @size: the allocated size of @buf * - * Converts an #hb_variation_t into a %NULL-terminated string in the format + * Converts an #hb_variation_t into a `NULL`-terminated string in the format * understood by hb_variation_from_string(). The client in responsible for * allocating big enough size for @buf, 128 bytes is more than enough. * @@ -1134,7 +1140,7 @@ hb_variation_to_string (hb_variation_t *variation, assert (len < ARRAY_LENGTH (s)); len = hb_min (len, size - 1); - memcpy (buf, s, len); + hb_memcpy (buf, s, len); buf[len] = '\0'; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-common.h b/src/java.desktop/share/native/libharfbuzz/hb-common.h index 95daf0ed6a2..ebdeadd1fd1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-common.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-common.h @@ -326,6 +326,9 @@ hb_language_to_string (hb_language_t language); HB_EXTERN hb_language_t hb_language_get_default (void); +HB_EXTERN hb_bool_t +hb_language_matches (hb_language_t language, + hb_language_t specific); /** * hb_script_t: @@ -492,6 +495,8 @@ hb_language_get_default (void); * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0 * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0 * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0 + * @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0 + * @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0 * @HB_SCRIPT_INVALID: No script set * * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding @@ -713,6 +718,12 @@ typedef enum */ HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'), + /* + * Since 5.2.0 + */ + HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/ + HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/ + /* No script set. */ HB_SCRIPT_INVALID = HB_TAG_NONE, @@ -886,6 +897,32 @@ HB_EXTERN uint8_t hb_color_get_blue (hb_color_t color); #define hb_color_get_blue(color) (((color) >> 24) & 0xFF) +/** + * hb_glyph_extents_t: + * @x_bearing: Distance from the x-origin to the left extremum of the glyph. + * @y_bearing: Distance from the top extremum of the glyph to the y-origin. + * @width: Distance from the left extremum of the glyph to the right extremum. + * @height: Distance from the top extremum of the glyph to the bottom extremum. + * + * Glyph extent values, measured in font units. + * + * Note that @height is negative, in coordinate systems that grow up. + **/ +typedef struct hb_glyph_extents_t { + hb_position_t x_bearing; + hb_position_t y_bearing; + hb_position_t width; + hb_position_t height; +} hb_glyph_extents_t; + +/** + * hb_font_t: + * + * Data type for holding fonts. + * + */ +typedef struct hb_font_t hb_font_t; + HB_END_DECLS #endif /* HB_COMMON_H */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-config.hh b/src/java.desktop/share/native/libharfbuzz/hb-config.hh index 2578231d238..047518b87d4 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-config.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-config.hh @@ -35,6 +35,11 @@ #include "config.h" #endif +#ifndef HB_EXPERIMENTAL_API +#define HB_NO_BEYOND_64K +#define HB_NO_CUBIC_GLYF +#define HB_NO_VAR_COMPOSITES +#endif #ifdef HB_TINY #define HB_LEAN @@ -68,6 +73,7 @@ #define HB_NO_LANGUAGE_PRIVATE_SUBTAG #define HB_NO_LAYOUT_FEATURE_PARAMS #define HB_NO_LAYOUT_COLLECT_GLYPHS +#define HB_NO_LAYOUT_RARELY_USED #define HB_NO_LAYOUT_UNUSED #define HB_NO_MATH #define HB_NO_META @@ -75,11 +81,13 @@ #define HB_NO_MMAP #define HB_NO_NAME #define HB_NO_OPEN -#define HB_NO_SETLOCALE #define HB_NO_OT_FONT_GLYPH_NAMES #define HB_NO_OT_SHAPE_FRACTIONS +#define HB_NO_PAINT +#define HB_NO_SETLOCALE #define HB_NO_STYLE #define HB_NO_SUBSET_LAYOUT +#define HB_NO_VERTICAL #define HB_NO_VAR #endif @@ -98,12 +106,22 @@ /* Closure of options. */ +#ifdef HB_NO_BORING_EXPANSION +#define HB_NO_BEYOND_64K +#define HB_NO_AVAR2 +#endif + #ifdef HB_DISABLE_DEPRECATED #define HB_IF_NOT_DEPRECATED(x) #else #define HB_IF_NOT_DEPRECATED(x) x #endif +#ifdef HB_NO_SHAPER +#define HB_NO_OT_SHAPE +#define HB_NO_AAT_SHAPE +#endif + #ifdef HB_NO_AAT #define HB_NO_OT_NAME_LANGUAGE_AAT #define HB_NO_AAT_SHAPE @@ -150,6 +168,7 @@ #define HB_NO_OT_SHAPER_HEBREW_FALLBACK #define HB_NO_OT_SHAPER_THAI_FALLBACK #define HB_NO_OT_SHAPER_VOWEL_CONSTRAINTS +#define HB_NO_OT_SHAPER_MYANMAR_ZAWGYI #endif #ifdef NDEBUG diff --git a/src/java.desktop/share/native/libharfbuzz/hb-cplusplus.hh b/src/java.desktop/share/native/libharfbuzz/hb-cplusplus.hh index adfbc3c11bf..eac4ff03ed5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-cplusplus.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-cplusplus.hh @@ -69,9 +69,9 @@ struct shared_ptr operator T * () const { return p; } T& operator * () const { return *get (); } T* operator -> () const { return get (); } - operator bool () { return p; } - bool operator == (const shared_ptr &o) { return p == o.p; } - bool operator != (const shared_ptr &o) { return p != o.p; } + operator bool () const { return p; } + bool operator == (const shared_ptr &o) const { return p == o.p; } + bool operator != (const shared_ptr &o) const { return p != o.p; } static T* get_empty() { return v::get_empty (); } T* reference() { return v::reference (p); } @@ -130,7 +130,7 @@ template struct vtable_t { @@ -160,14 +160,43 @@ HB_DEFINE_VTABLE (map); HB_DEFINE_VTABLE (set); HB_DEFINE_VTABLE (shape_plan); HB_DEFINE_VTABLE (unicode_funcs); +HB_DEFINE_VTABLE (draw_funcs); +HB_DEFINE_VTABLE (paint_funcs); #undef HB_DEFINE_VTABLE +#ifdef HB_SUBSET_H + +#define HB_DEFINE_VTABLE(name) \ + template<> \ + struct vtable \ + : vtable_t {} + + +HB_DEFINE_VTABLE (subset_input); +HB_DEFINE_VTABLE (subset_plan); + +#undef HB_DEFINE_VTABLE + +#endif + + } // namespace hb +/* Workaround for GCC < 7, see: + * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56480 + * https://stackoverflow.com/a/25594741 */ +namespace std { + + template -struct std::hash> +struct hash> { std::size_t operator()(const hb::shared_ptr& v) const noexcept { @@ -177,7 +206,7 @@ struct std::hash> }; template -struct std::hash> +struct hash> { std::size_t operator()(const hb::unique_ptr& v) const noexcept { @@ -187,6 +216,8 @@ struct std::hash> }; +} // namespace std + #endif /* __cplusplus */ #endif /* HB_CPLUSPLUS_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh index 09c407e415d..43647c259f6 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-debug.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-debug.hh @@ -67,12 +67,12 @@ hb_options () #endif /* Make a local copy, so we can access bitfield threadsafely. */ hb_options_union_t u; - u.i = _hb_options.get_relaxed (); + u.i = _hb_options; if (unlikely (!u.i)) { _hb_options_init (); - u.i = _hb_options.get_relaxed (); + u.i = _hb_options; } return u.opts; @@ -113,7 +113,7 @@ _hb_print_func (const char *func) const char *paren = strchr (func, '('); if (paren) func_len = paren - func; - fprintf (stderr, "%.*s", func_len, func); + fprintf (stderr, "%.*s", (int) func_len, func); } } @@ -142,9 +142,9 @@ _hb_debug_msg_va (const char *what, fprintf (stderr, "%-10s", what ? what : ""); if (obj) - fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj); + fprintf (stderr, "(%*p) ", (int) (2 * sizeof (void *)), obj); else - fprintf (stderr, " %*s ", (unsigned int) (2 * sizeof (void *)), ""); + fprintf (stderr, " %*s ", (int) (2 * sizeof (void *)), ""); if (indented) { #define VBAR "\342\224\202" /* U+2502 BOX DRAWINGS LIGHT VERTICAL */ @@ -306,7 +306,7 @@ struct hb_auto_trace_t } _hb_debug_msg (what, obj, func, true, plevel ? *plevel : 1, -1, - "return %s (line %d)", + "return %s (line %u)", hb_printer_t>().print (v), line); if (plevel) --*plevel; plevel = nullptr; @@ -396,7 +396,7 @@ struct hb_no_trace_t { #define TRACE_APPLY(this) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - "idx %d gid %u lookup %d", \ + "idx %u gid %u lookup %d", \ c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index) #else #define TRACE_APPLY(this) hb_no_trace_t trace @@ -454,10 +454,15 @@ struct hb_no_trace_t { #define TRACE_DISPATCH(this, format) \ hb_auto_trace_t trace \ (&c->debug_depth, c->get_name (), this, HB_FUNC, \ - "format %d", (int) format) + "format %u", (unsigned) format) #else #define TRACE_DISPATCH(this, format) hb_no_trace_t trace #endif +#ifndef HB_BUFFER_MESSAGE_MORE +#define HB_BUFFER_MESSAGE_MORE (HB_DEBUG+1) +#endif + + #endif /* HB_DEBUG_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h index 55f1e1205df..c6b67291878 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-deprecated.h @@ -93,7 +93,7 @@ HB_BEGIN_DECLS * This method should retrieve the glyph ID for a specified Unicode code point * font, with an optional variation selector. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * Deprecated: 1.2.3 * **/ @@ -102,7 +102,8 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t *glyph, void *user_data); -HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void +HB_DEPRECATED_FOR (hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) +HB_EXTERN void hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_func_t func, void *user_data, hb_destroy_func_t destroy); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc index 6a9ab012409..f2821578b65 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-draw.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.cc @@ -35,6 +35,8 @@ * @include: hb.h * * Functions for drawing (extracting) glyph shapes. + * + * The #hb_draw_funcs_t struct can be used with hb_font_draw_glyph(). **/ static void @@ -80,6 +82,56 @@ hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UN void *user_data HB_UNUSED) {} +static bool +_hb_draw_funcs_set_preamble (hb_draw_funcs_t *dfuncs, + bool func_is_null, + void **user_data, + hb_destroy_func_t *destroy) +{ + if (hb_object_is_immutable (dfuncs)) + { + if (*destroy) + (*destroy) (*user_data); + return false; + } + + if (func_is_null) + { + if (*destroy) + (*destroy) (*user_data); + *destroy = nullptr; + *user_data = nullptr; + } + + return true; +} + +static bool +_hb_draw_funcs_set_middle (hb_draw_funcs_t *dfuncs, + void *user_data, + hb_destroy_func_t destroy) +{ + if (user_data && !dfuncs->user_data) + { + dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); + if (unlikely (!dfuncs->user_data)) + goto fail; + } + if (destroy && !dfuncs->destroy) + { + dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); + if (unlikely (!dfuncs->destroy)) + goto fail; + } + + return true; + +fail: + if (destroy) + (destroy) (user_data); + return false; +} + #define HB_DRAW_FUNC_IMPLEMENT(name) \ \ void \ @@ -88,42 +140,24 @@ hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, void *user_data, \ hb_destroy_func_t destroy) \ { \ - if (hb_object_is_immutable (dfuncs)) \ - return; \ + if (!_hb_draw_funcs_set_preamble (dfuncs, !func, &user_data, &destroy))\ + return; \ \ if (dfuncs->destroy && dfuncs->destroy->name) \ dfuncs->destroy->name (!dfuncs->user_data ? nullptr : dfuncs->user_data->name); \ \ - if (user_data && !dfuncs->user_data) \ - { \ - dfuncs->user_data = (decltype (dfuncs->user_data)) hb_calloc (1, sizeof (*dfuncs->user_data)); \ - if (unlikely (!dfuncs->user_data)) \ - goto fail; \ - } \ - if (destroy && !dfuncs->destroy) \ - { \ - dfuncs->destroy = (decltype (dfuncs->destroy)) hb_calloc (1, sizeof (*dfuncs->destroy)); \ - if (unlikely (!dfuncs->destroy)) \ - goto fail; \ - } \ + if (!_hb_draw_funcs_set_middle (dfuncs, user_data, destroy)) \ + return; \ \ - if (func) { \ + if (func) \ dfuncs->func.name = func; \ - if (dfuncs->user_data) \ - dfuncs->user_data->name = user_data; \ - if (dfuncs->destroy) \ - dfuncs->destroy->name = destroy; \ - } else { \ + else \ dfuncs->func.name = hb_draw_##name##_nil; \ - if (dfuncs->user_data) \ - dfuncs->user_data->name = nullptr; \ - if (dfuncs->destroy) \ - dfuncs->destroy->name = nullptr; \ - } \ - \ -fail: \ - if (destroy) \ - destroy (user_data); \ + \ + if (dfuncs->user_data) \ + dfuncs->user_data->name = user_data; \ + if (dfuncs->destroy) \ + dfuncs->destroy->name = destroy; \ } HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS @@ -137,7 +171,7 @@ HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS * Return value: (transfer full): * A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial * reference count should be released with hb_draw_funcs_destroy when you are - * done using the #hb_draw_funcs_t. This function never returns %NULL. If + * done using the #hb_draw_funcs_t. This function never returns `NULL`. If * memory cannot be allocated, a special singleton #hb_draw_funcs_t object will * be returned. * @@ -166,13 +200,29 @@ DEFINE_NULL_INSTANCE (hb_draw_funcs_t) = } }; +/** + * hb_draw_funcs_get_empty: + * + * Fetches the singleton empty draw-functions structure. + * + * Return value: (transfer full): The empty draw-functions structure + * + * Since: 7.0.0 + **/ +hb_draw_funcs_t * +hb_draw_funcs_get_empty () +{ + return const_cast (&Null (hb_draw_funcs_t)); +} /** * hb_draw_funcs_reference: (skip) * @dfuncs: draw functions * - * Increases the reference count on @dfuncs by one. This prevents @buffer from - * being destroyed until a matching call to hb_draw_funcs_destroy() is made. + * Increases the reference count on @dfuncs by one. + * + * This prevents @dfuncs from being destroyed until a matching + * call to hb_draw_funcs_destroy() is made. * * Return value: (transfer full): * The referenced #hb_draw_funcs_t. @@ -208,9 +258,55 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs) #undef HB_DRAW_FUNC_IMPLEMENT } + hb_free (dfuncs->destroy); + hb_free (dfuncs->user_data); + hb_free (dfuncs); } +/** + * hb_draw_funcs_set_user_data: (skip) + * @dfuncs: The draw-functions structure + * @key: The user-data key + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key + * + * Attaches a user-data key/data pair to the specified draw-functions structure. + * + * Return value: `true` if success, `false` otherwise + * + * Since: 7.0.0 + **/ +hb_bool_t +hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (dfuncs, key, data, destroy, replace); +} + +/** + * hb_draw_funcs_get_user_data: (skip) + * @dfuncs: The draw-functions structure + * @key: The user-data key to query + * + * Fetches the user-data associated with the specified key, + * attached to the specified draw-functions structure. + * + * Return value: (transfer none): A pointer to the user data + * + * Since: 7.0.0 + **/ +void * +hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (dfuncs, key); +} + /** * hb_draw_funcs_make_immutable: * @dfuncs: draw functions @@ -234,7 +330,7 @@ hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs) * * Checks whether @dfuncs is immutable. * - * Return value: %true if @dfuncs is immutable, %false otherwise + * Return value: `true` if @dfuncs is immutable, `false` otherwise * * Since: 4.0.0 **/ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-draw.h b/src/java.desktop/share/native/libharfbuzz/hb-draw.h index 364db5f7f56..eba791d10c0 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-draw.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-draw.h @@ -92,11 +92,11 @@ typedef struct hb_draw_funcs_t hb_draw_funcs_t; /** * hb_draw_move_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_move_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw * operation. @@ -112,11 +112,11 @@ typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data /** * hb_draw_line_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_line_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw * operation. @@ -132,13 +132,13 @@ typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data /** * hb_draw_quadratic_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @control_x: X component of control point * @control_y: Y component of control point * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_quadratic_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw * operation. @@ -155,7 +155,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw /** * hb_draw_cubic_to_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state * @control1_x: X component of first control point * @control1_y: Y component of first control point @@ -163,7 +163,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw * @control2_y: Y component of second control point * @to_x: X component of target point * @to_y: Y component of target point - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_cubic_to_func() * * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw * operation. @@ -181,9 +181,9 @@ typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_dat /** * hb_draw_close_path_func_t: * @dfuncs: draw functions object - * @draw_data: The data accompanying the draw functions + * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph() * @st: current draw state - * @user_data: User data pointer passed by the caller + * @user_data: User data pointer passed to hb_draw_funcs_set_close_path_func() * * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw * operation. @@ -279,12 +279,27 @@ hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs, HB_EXTERN hb_draw_funcs_t * hb_draw_funcs_create (void); +HB_EXTERN hb_draw_funcs_t * +hb_draw_funcs_get_empty (void); + HB_EXTERN hb_draw_funcs_t * hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs); HB_EXTERN void hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs); +HB_EXTERN hb_bool_t +hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace); + + +HB_EXTERN void * +hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs, + hb_user_data_key_t *key); + HB_EXTERN void hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc b/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc new file mode 100644 index 00000000000..ff723ac7000 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-face-builder.cc @@ -0,0 +1,246 @@ +/* + * Copyright © 2009 Red Hat, Inc. + * Copyright © 2012 Google, Inc. + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Red Hat Author(s): Behdad Esfahbod + * Google Author(s): Behdad Esfahbod + */ + +#include "hb.hh" + +#include "hb-face.hh" + +#include "hb-map.hh" +#include "hb-open-file.hh" +#include "hb-serialize.hh" + + +/* + * face-builder: A face that has add_table(). + */ + +struct face_table_info_t +{ + hb_blob_t* data; + signed order; +}; + +struct hb_face_builder_data_t +{ + hb_hashmap_t tables; +}; + +static int compare_entries (const void* pa, const void* pb) +{ + const auto& a = * (const hb_pair_t *) pa; + const auto& b = * (const hb_pair_t *) pb; + + /* Order by blob size first (smallest to largest) and then table tag */ + + if (a.second.order != b.second.order) + return a.second.order < b.second.order ? -1 : +1; + + if (a.second.data->length != b.second.data->length) + return a.second.data->length < b.second.data->length ? -1 : +1; + + return a.first < b.first ? -1 : a.first == b.first ? 0 : +1; +} + +static hb_face_builder_data_t * +_hb_face_builder_data_create () +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_calloc (1, sizeof (hb_face_builder_data_t)); + if (unlikely (!data)) + return nullptr; + + data->tables.init (); + + return data; +} + +static void +_hb_face_builder_data_destroy (void *user_data) +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; + + for (auto info : data->tables.values()) + hb_blob_destroy (info.data); + + data->tables.fini (); + + hb_free (data); +} + +static hb_blob_t * +_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data) +{ + + unsigned int table_count = data->tables.get_population (); + unsigned int face_length = table_count * 16 + 12; + + for (auto info : data->tables.values()) + face_length += hb_ceil_to_4 (hb_blob_get_length (info.data)); + + char *buf = (char *) hb_malloc (face_length); + if (unlikely (!buf)) + return nullptr; + + hb_serialize_context_t c (buf, face_length); + c.propagate_error (data->tables); + OT::OpenTypeFontFile *f = c.start_serialize (); + + bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' ')) + || data->tables.has (HB_TAG ('C','F','F','2'))); + hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; + + // Sort the tags so that produced face is deterministic. + hb_vector_t> sorted_entries; + data->tables.iter () | hb_sink (sorted_entries); + if (unlikely (sorted_entries.in_error ())) + { + hb_free (buf); + return nullptr; + } + + sorted_entries.qsort (compare_entries); + + bool ret = f->serialize_single (&c, + sfnt_tag, + + sorted_entries.iter() + | hb_map ([&] (hb_pair_t _) { + return hb_pair_t (_.first, _.second.data); + })); + + c.end_serialize (); + + if (unlikely (!ret)) + { + hb_free (buf); + return nullptr; + } + + return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free); +} + +static hb_blob_t * +_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +{ + hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; + + if (!tag) + return _hb_face_builder_data_reference_blob (data); + + return hb_blob_reference (data->tables[tag].data); +} + + +/** + * hb_face_builder_create: + * + * Creates a #hb_face_t that can be used with hb_face_builder_add_table(). + * After tables are added to the face, it can be compiled to a binary + * font file by calling hb_face_reference_blob(). + * + * Return value: (transfer full): New face. + * + * Since: 1.9.0 + **/ +hb_face_t * +hb_face_builder_create () +{ + hb_face_builder_data_t *data = _hb_face_builder_data_create (); + if (unlikely (!data)) return hb_face_get_empty (); + + return hb_face_create_for_tables (_hb_face_builder_reference_table, + data, + _hb_face_builder_data_destroy); +} + +/** + * hb_face_builder_add_table: + * @face: A face object created with hb_face_builder_create() + * @tag: The #hb_tag_t of the table to add + * @blob: The blob containing the table data to add + * + * Add table for @tag with data provided by @blob to the face. @face must + * be created using hb_face_builder_create(). + * + * Since: 1.9.0 + **/ +hb_bool_t +hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) +{ + if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy)) + return false; + + if (tag == HB_MAP_VALUE_INVALID) + return false; + + hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; + + hb_blob_t* previous = data->tables.get (tag).data; + if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1})) + { + hb_blob_destroy (blob); + return false; + } + + hb_blob_destroy (previous); + return true; +} + +/** + * hb_face_builder_sort_tables: + * @face: A face object created with hb_face_builder_create() + * @tags: (array zero-terminated=1): ordered list of table tags terminated by + * %HB_TAG_NONE + * + * Set the ordering of tables for serialization. Any tables not + * specified in the tags list will be ordered after the tables in + * tags, ordered by the default sort ordering. + * + * Since: 5.3.0 + **/ +void +hb_face_builder_sort_tables (hb_face_t *face, + const hb_tag_t *tags) +{ + if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy)) + return; + + hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; + + // Sort all unspecified tables after any specified tables. + for (auto& info : data->tables.values_ref()) + info.order = (unsigned) -1; + + signed order = 0; + for (const hb_tag_t* tag = tags; + *tag; + tag++) + { + face_table_info_t* info; + if (!data->tables.has (*tag, &info)) continue; + info->order = order++; + } +} diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.cc b/src/java.desktop/share/native/libharfbuzz/hb-face.cc index 43a32484701..8bb9f16af94 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-face.cc @@ -33,7 +33,6 @@ #include "hb-open-file.hh" #include "hb-ot-face.hh" #include "hb-ot-cmap-table.hh" -#include "hb-map.hh" /** @@ -132,7 +131,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, face->user_data = user_data; face->destroy = destroy; - face->num_glyphs.set_relaxed (-1); + face->num_glyphs = -1; face->data.init0 (face); face->table.init0 (face); @@ -288,6 +287,7 @@ hb_face_destroy (hb_face_t *face) { if (!hb_object_destroy (face)) return; +#ifndef HB_NO_SHAPER for (hb_face_t::plan_node_t *node = face->shape_plans; node; ) { hb_face_t::plan_node_t *next = node->next; @@ -295,6 +295,7 @@ hb_face_destroy (hb_face_t *face) hb_free (node); node = next; } +#endif face->data.fini (); face->table.fini (); @@ -315,7 +316,7 @@ hb_face_destroy (hb_face_t *face) * * Attaches a user-data key/data pair to the given face object. * - * Return value: %true if success, %false otherwise + * Return value: `true` if success, `false` otherwise * * Since: 0.9.2 **/ @@ -342,7 +343,7 @@ hb_face_set_user_data (hb_face_t *face, * Since: 0.9.2 **/ void * -hb_face_get_user_data (hb_face_t *face, +hb_face_get_user_data (const hb_face_t *face, hb_user_data_key_t *key) { return hb_object_get_user_data (face, key); @@ -371,7 +372,7 @@ hb_face_make_immutable (hb_face_t *face) * * Tests whether the given face object is immutable. * - * Return value: %true is @face is immutable, %false otherwise + * Return value: `true` is @face is immutable, `false` otherwise * * Since: 0.9.2 **/ @@ -470,6 +471,8 @@ hb_face_get_index (const hb_face_t *face) * * Sets the units-per-em (upem) for a face object to the specified value. * + * This API is used in rare circumstances. + * * Since: 0.9.2 **/ void @@ -479,14 +482,17 @@ hb_face_set_upem (hb_face_t *face, if (hb_object_is_immutable (face)) return; - face->upem.set_relaxed (upem); + face->upem = upem; } /** * hb_face_get_upem: * @face: A face object * - * Fetches the units-per-em (upem) value of the specified face object. + * Fetches the units-per-em (UPEM) value of the specified face object. + * + * Typical UPEM values for fonts are 1000, or 2048, but any value + * in between 16 and 16,384 is allowed for OpenType fonts. * * Return value: The upem value of @face * @@ -505,6 +511,8 @@ hb_face_get_upem (const hb_face_t *face) * * Sets the glyph count for a face object to the specified value. * + * This API is used in rare circumstances. + * * Since: 0.9.7 **/ void @@ -514,7 +522,7 @@ hb_face_set_glyph_count (hb_face_t *face, if (hb_object_is_immutable (face)) return; - face->num_glyphs.set_relaxed (glyph_count); + face->num_glyphs = glyph_count; } /** @@ -579,7 +587,7 @@ hb_face_get_table_tags (const hb_face_t *face, /** * hb_face_collect_unicodes: * @face: A face object - * @out: The set to add Unicode characters to + * @out: (out): The set to add Unicode characters to * * Collects all of the Unicode characters covered by @face and adds * them to the #hb_set_t set @out. @@ -592,10 +600,31 @@ hb_face_collect_unicodes (hb_face_t *face, { face->table.cmap->collect_unicodes (out, face->get_num_glyphs ()); } +/** + * hb_face_collect_nominal_glyph_mapping: + * @face: A face object + * @mapping: (out): The map to add Unicode-to-glyph mapping to + * @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL` + * + * Collects the mapping from Unicode characters to nominal glyphs of the @face, + * and optionally all of the Unicode characters covered by @face. + * + * Since: 7.0.0 + */ +void +hb_face_collect_nominal_glyph_mapping (hb_face_t *face, + hb_map_t *mapping, + hb_set_t *unicodes) +{ + hb_set_t stack_unicodes; + if (!unicodes) + unicodes = &stack_unicodes; + face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ()); +} /** * hb_face_collect_variation_selectors: * @face: A face object - * @out: The set to add Variation Selector characters to + * @out: (out): The set to add Variation Selector characters to * * Collects all Unicode "Variation Selector" characters covered by @face and adds * them to the #hb_set_t set @out. @@ -612,7 +641,7 @@ hb_face_collect_variation_selectors (hb_face_t *face, * hb_face_collect_variation_unicodes: * @face: A face object * @variation_selector: The Variation Selector to query - * @out: The set to add Unicode characters to + * @out: (out): The set to add Unicode characters to * * Collects all Unicode characters for @variation_selector covered by @face and adds * them to the #hb_set_t set @out. @@ -627,163 +656,3 @@ hb_face_collect_variation_unicodes (hb_face_t *face, face->table.cmap->collect_variation_unicodes (variation_selector, out); } #endif - - -/* - * face-builder: A face that has add_table(). - */ - -struct hb_face_builder_data_t -{ - hb_hashmap_t tables; -}; - -static int compare_entries (const void* pa, const void* pb) -{ - const auto& a = * (const hb_pair_t *) pa; - const auto& b = * (const hb_pair_t *) pb; - - /* Order by blob size first (smallest to largest) and then table tag */ - - if (a.second->length != b.second->length) - return a.second->length < b.second->length ? -1 : +1; - - return a.first < b.first ? -1 : a.first == b.first ? 0 : +1; -} - -static hb_face_builder_data_t * -_hb_face_builder_data_create () -{ - hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_calloc (1, sizeof (hb_face_builder_data_t)); - if (unlikely (!data)) - return nullptr; - - data->tables.init (); - - return data; -} - -static void -_hb_face_builder_data_destroy (void *user_data) -{ - hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; - - for (hb_blob_t* b : data->tables.values()) - hb_blob_destroy (b); - - data->tables.fini (); - - hb_free (data); -} - -static hb_blob_t * -_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data) -{ - - unsigned int table_count = data->tables.get_population (); - unsigned int face_length = table_count * 16 + 12; - - for (hb_blob_t* b : data->tables.values()) - face_length += hb_ceil_to_4 (hb_blob_get_length (b)); - - char *buf = (char *) hb_malloc (face_length); - if (unlikely (!buf)) - return nullptr; - - hb_serialize_context_t c (buf, face_length); - c.propagate_error (data->tables); - OT::OpenTypeFontFile *f = c.start_serialize (); - - bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' ')) - || data->tables.has (HB_TAG ('C','F','F','2'))); - hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag; - - // Sort the tags so that produced face is deterministic. - hb_vector_t> sorted_entries; - data->tables.iter () | hb_sink (sorted_entries); - if (unlikely (sorted_entries.in_error ())) - { - hb_free (buf); - return nullptr; - } - - sorted_entries.qsort (compare_entries); - bool ret = f->serialize_single (&c, sfnt_tag, + sorted_entries.iter()); - - c.end_serialize (); - - if (unlikely (!ret)) - { - hb_free (buf); - return nullptr; - } - - return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free); -} - -static hb_blob_t * -_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) -{ - hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data; - - if (!tag) - return _hb_face_builder_data_reference_blob (data); - - return hb_blob_reference (data->tables[tag]); -} - - -/** - * hb_face_builder_create: - * - * Creates a #hb_face_t that can be used with hb_face_builder_add_table(). - * After tables are added to the face, it can be compiled to a binary - * font file by calling hb_face_reference_blob(). - * - * Return value: (transfer full): New face. - * - * Since: 1.9.0 - **/ -hb_face_t * -hb_face_builder_create () -{ - hb_face_builder_data_t *data = _hb_face_builder_data_create (); - if (unlikely (!data)) return hb_face_get_empty (); - - return hb_face_create_for_tables (_hb_face_builder_reference_table, - data, - _hb_face_builder_data_destroy); -} - -/** - * hb_face_builder_add_table: - * @face: A face object created with hb_face_builder_create() - * @tag: The #hb_tag_t of the table to add - * @blob: The blob containing the table data to add - * - * Add table for @tag with data provided by @blob to the face. @face must - * be created using hb_face_builder_create(). - * - * Since: 1.9.0 - **/ -hb_bool_t -hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob) -{ - if (tag == HB_MAP_VALUE_INVALID) - return false; - - if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy)) - return false; - - hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data; - - hb_blob_t* previous = data->tables.get (tag); - if (!data->tables.set (tag, hb_blob_reference (blob))) - { - hb_blob_destroy (blob); - return false; - } - - hb_blob_destroy (previous); - return true; -} diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.h b/src/java.desktop/share/native/libharfbuzz/hb-face.h index e74db2933b9..2e5fb150927 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-face.h @@ -33,6 +33,7 @@ #include "hb-common.h" #include "hb-blob.h" +#include "hb-map.h" #include "hb-set.h" HB_BEGIN_DECLS @@ -96,7 +97,7 @@ hb_face_set_user_data (hb_face_t *face, hb_bool_t replace); HB_EXTERN void * -hb_face_get_user_data (hb_face_t *face, +hb_face_get_user_data (const hb_face_t *face, hb_user_data_key_t *key); HB_EXTERN void @@ -149,6 +150,11 @@ HB_EXTERN void hb_face_collect_unicodes (hb_face_t *face, hb_set_t *out); +HB_EXTERN void +hb_face_collect_nominal_glyph_mapping (hb_face_t *face, + hb_map_t *mapping, + hb_set_t *unicodes); + HB_EXTERN void hb_face_collect_variation_selectors (hb_face_t *face, hb_set_t *out); @@ -171,6 +177,10 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob); +HB_EXTERN void +hb_face_builder_sort_tables (hb_face_t *face, + const hb_tag_t *tags); + HB_END_DECLS diff --git a/src/java.desktop/share/native/libharfbuzz/hb-face.hh b/src/java.desktop/share/native/libharfbuzz/hb-face.hh index b4a74e9580f..738f7ecdc72 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-face.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-face.hh @@ -65,7 +65,9 @@ struct hb_face_t hb_shape_plan_t *shape_plan; plan_node_t *next; }; +#ifndef HB_NO_SHAPER hb_atomic_ptr_t shape_plans; +#endif hb_blob_t *reference_table (hb_tag_t tag) const { @@ -83,7 +85,7 @@ struct hb_face_t unsigned int get_upem () const { - unsigned int ret = upem.get_relaxed (); + unsigned int ret = upem; if (unlikely (!ret)) { return load_upem (); @@ -93,7 +95,7 @@ struct hb_face_t unsigned int get_num_glyphs () const { - unsigned int ret = num_glyphs.get_relaxed (); + unsigned int ret = num_glyphs; if (unlikely (ret == UINT_MAX)) return load_num_glyphs (); return ret; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc b/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc index cd1eaf5e21f..e37f90111eb 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-fallback-shape.cc @@ -75,16 +75,6 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED, const hb_feature_t *features HB_UNUSED, unsigned int num_features HB_UNUSED) { - /* TODO - * - * - Apply fallback kern. - * - Handle Variation Selectors? - * - Apply normalization? - * - * This will make the fallback shaper into a dumb "TrueType" - * shaper which many people unfortunately still request. - */ - hb_codepoint_t space; bool has_space = (bool) font->get_nominal_glyph (' ', &space); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-font.cc index b36b53613f8..d118deb9285 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.cc @@ -30,6 +30,7 @@ #include "hb-font.hh" #include "hb-draw.hh" +#include "hb-paint.hh" #include "hb-machinery.hh" #include "hb-ot.h" @@ -71,7 +72,7 @@ hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED, hb_font_extents_t *extents, void *user_data HB_UNUSED) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return false; } @@ -96,7 +97,7 @@ hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED, hb_font_extents_t *extents, void *user_data HB_UNUSED) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return false; } @@ -409,7 +410,7 @@ hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED, hb_glyph_extents_t *extents, void *user_data HB_UNUSED) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return false; } @@ -503,22 +504,34 @@ hb_font_get_glyph_from_name_default (hb_font_t *font, } static void -hb_font_get_glyph_shape_nil (hb_font_t *font HB_UNUSED, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, - void *draw_data, - void *user_data HB_UNUSED) +hb_font_draw_glyph_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, + void *draw_data, + void *user_data HB_UNUSED) { } +static void +hb_font_paint_glyph_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + hb_paint_funcs_t *paint_funcs HB_UNUSED, + void *paint_data HB_UNUSED, + unsigned int palette HB_UNUSED, + hb_color_t foreground HB_UNUSED, + void *user_data HB_UNUSED) +{ +} -typedef struct hb_font_get_glyph_shape_default_adaptor_t { +typedef struct hb_font_draw_glyph_default_adaptor_t { hb_draw_funcs_t *draw_funcs; void *draw_data; float x_scale; float y_scale; -} hb_font_get_glyph_shape_default_adaptor_t; + float slant; +} hb_font_draw_glyph_default_adaptor_t; static void hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, @@ -527,12 +540,13 @@ hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st, - x_scale * to_x, y_scale * to_y); + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -541,15 +555,16 @@ hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; - st->current_x *= x_scale; - st->current_y *= y_scale; + st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st, - x_scale * to_x, y_scale * to_y); + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -559,16 +574,17 @@ hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; - st->current_x *= x_scale; - st->current_y *= y_scale; + st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st, - x_scale * control_x, y_scale * control_y, - x_scale * to_x, y_scale * to_y); + x_scale * control_x + slant * control_y, y_scale * control_y, + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -579,17 +595,18 @@ hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, float to_x, float to_y, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; float x_scale = adaptor->x_scale; float y_scale = adaptor->y_scale; + float slant = adaptor->slant; - st->current_x *= x_scale; - st->current_y *= y_scale; + st->current_x = st->current_x * x_scale + st->current_y * slant; + st->current_y = st->current_y * y_scale; adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st, - x_scale * control1_x, y_scale * control1_y, - x_scale * control2_x, y_scale * control2_y, - x_scale * to_x, y_scale * to_y); + x_scale * control1_x + slant * control1_y, y_scale * control1_y, + x_scale * control2_x + slant * control2_y, y_scale * control2_y, + x_scale * to_x + slant * to_y, y_scale * to_y); } static void @@ -597,7 +614,7 @@ hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, hb_draw_state_t *st, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + hb_font_draw_glyph_default_adaptor_t *adaptor = (hb_font_draw_glyph_default_adaptor_t *) draw_data; adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st); } @@ -613,25 +630,50 @@ static const hb_draw_funcs_t _hb_draw_funcs_default = { }; static void -hb_font_get_glyph_shape_default (hb_font_t *font, +hb_font_draw_glyph_default (hb_font_t *font, void *font_data HB_UNUSED, hb_codepoint_t glyph, hb_draw_funcs_t *draw_funcs, void *draw_data, void *user_data HB_UNUSED) { - hb_font_get_glyph_shape_default_adaptor_t adaptor = { + hb_font_draw_glyph_default_adaptor_t adaptor = { draw_funcs, draw_data, - (float) font->x_scale / (float) font->parent->x_scale, - (float) font->y_scale / (float) font->parent->y_scale + font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f, + font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f, + font->parent->y_scale ? (font->slant - font->parent->slant) * + (float) font->x_scale / (float) font->parent->y_scale : 0.f }; - font->parent->get_glyph_shape (glyph, + font->parent->draw_glyph (glyph, const_cast (&_hb_draw_funcs_default), &adaptor); } +static void +hb_font_paint_glyph_default (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, + void *paint_data, + unsigned int palette, + hb_color_t foreground, + void *user_data) +{ + paint_funcs->push_transform (paint_data, + font->parent->x_scale ? (float) font->x_scale / (float) font->parent->x_scale : 0.f, + font->parent->y_scale ? (font->slant - font->parent->slant) * + (float) font->x_scale / (float) font->parent->y_scale : 0.f, + 0.f, + font->parent->y_scale ? (float) font->y_scale / (float) font->parent->y_scale : 0.f, + 0.f, 0.f); + + font->parent->paint_glyph (glyph, paint_funcs, paint_data, palette, foreground); + + paint_funcs->pop_transform (paint_data); +} + DEFINE_NULL_INSTANCE (hb_font_funcs_t) = { HB_OBJECT_HEADER_STATIC, @@ -640,7 +682,7 @@ DEFINE_NULL_INSTANCE (hb_font_funcs_t) = nullptr, { { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_nil, +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_nil, HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } @@ -654,7 +696,7 @@ static const hb_font_funcs_t _hb_font_funcs_default = { nullptr, { { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_default, +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_default, HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } @@ -732,7 +774,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) if (ffuncs->destroy) { -#define HB_FONT_FUNC_IMPLEMENT(name) if (ffuncs->destroy->name) \ +#define HB_FONT_FUNC_IMPLEMENT(get_,name) if (ffuncs->destroy->name) \ ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT @@ -754,7 +796,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) * * Attaches a user-data key/data pair to the specified font-functions structure. * - * Return value: %true if success, %false otherwise + * Return value: `true` if success, `false` otherwise * * Since: 0.9.2 **/ @@ -781,8 +823,8 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, * Since: 0.9.2 **/ void * -hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, - hb_user_data_key_t *key) +hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key) { return hb_object_get_user_data (ffuncs, key); } @@ -811,7 +853,7 @@ hb_font_funcs_make_immutable (hb_font_funcs_t *ffuncs) * * Tests whether a font-functions structure is immutable. * - * Return value: %true if @ffuncs is immutable, %false otherwise + * Return value: `true` if @ffuncs is immutable, `false` otherwise * * Since: 0.9.2 **/ @@ -822,59 +864,82 @@ hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs) } -#define HB_FONT_FUNC_IMPLEMENT(name) \ +static bool +_hb_font_funcs_set_preamble (hb_font_funcs_t *ffuncs, + bool func_is_null, + void **user_data, + hb_destroy_func_t *destroy) +{ + if (hb_object_is_immutable (ffuncs)) + { + if (*destroy) + (*destroy) (*user_data); + return false; + } + + if (func_is_null) + { + if (*destroy) + (*destroy) (*user_data); + *destroy = nullptr; + *user_data = nullptr; + } + + return true; +} + +static bool +_hb_font_funcs_set_middle (hb_font_funcs_t *ffuncs, + void *user_data, + hb_destroy_func_t destroy) +{ + if (user_data && !ffuncs->user_data) + { + ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); + if (unlikely (!ffuncs->user_data)) + goto fail; + } + if (destroy && !ffuncs->destroy) + { + ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); + if (unlikely (!ffuncs->destroy)) + goto fail; + } + + return true; + +fail: + if (destroy) + (destroy) (user_data); + return false; +} + +#define HB_FONT_FUNC_IMPLEMENT(get_,name) \ \ void \ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \ - hb_font_get_##name##_func_t func, \ + hb_font_##get_##name##_func_t func, \ void *user_data, \ hb_destroy_func_t destroy) \ { \ - if (hb_object_is_immutable (ffuncs)) \ - goto fail; \ - \ - if (!func) \ - { \ - if (destroy) \ - destroy (user_data); \ - destroy = nullptr; \ - user_data = nullptr; \ - } \ + if (!_hb_font_funcs_set_preamble (ffuncs, !func, &user_data, &destroy))\ + return; \ \ if (ffuncs->destroy && ffuncs->destroy->name) \ ffuncs->destroy->name (!ffuncs->user_data ? nullptr : ffuncs->user_data->name); \ \ - if (user_data && !ffuncs->user_data) \ - { \ - ffuncs->user_data = (decltype (ffuncs->user_data)) hb_calloc (1, sizeof (*ffuncs->user_data)); \ - if (unlikely (!ffuncs->user_data)) \ - goto fail; \ - } \ - if (destroy && !ffuncs->destroy) \ - { \ - ffuncs->destroy = (decltype (ffuncs->destroy)) hb_calloc (1, sizeof (*ffuncs->destroy)); \ - if (unlikely (!ffuncs->destroy)) \ - goto fail; \ - } \ + if (!_hb_font_funcs_set_middle (ffuncs, user_data, destroy)) \ + return; \ \ - if (func) { \ + if (func) \ ffuncs->get.f.name = func; \ - if (ffuncs->user_data) \ - ffuncs->user_data->name = user_data; \ - if (ffuncs->destroy) \ - ffuncs->destroy->name = destroy; \ - } else { \ - ffuncs->get.f.name = hb_font_get_##name##_default; \ - if (ffuncs->user_data) \ - ffuncs->user_data->name = nullptr; \ - if (ffuncs->destroy) \ - ffuncs->destroy->name = nullptr; \ - } \ - return; \ + else \ + ffuncs->get.f.name = hb_font_##get_##name##_default; \ \ -fail: \ - if (destroy) \ - destroy (user_data); \ + if (ffuncs->user_data) \ + ffuncs->user_data->name = user_data; \ + if (ffuncs->destroy) \ + ffuncs->destroy->name = destroy; \ } HB_FONT_FUNCS_IMPLEMENT_CALLBACKS @@ -903,7 +968,7 @@ hb_font_t::has_func (unsigned int i) * Fetches the extents for a specified font, for horizontal * text segments. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 1.1.3 **/ @@ -922,7 +987,7 @@ hb_font_get_h_extents (hb_font_t *font, * Fetches the extents for a specified font, for vertical * text segments. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 1.1.3 **/ @@ -946,7 +1011,7 @@ hb_font_get_v_extents (hb_font_t *font, * If @variation_selector is 0, calls hb_font_get_nominal_glyph(); * otherwise calls hb_font_get_variation_glyph(). * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 **/ @@ -974,7 +1039,7 @@ hb_font_get_glyph (hb_font_t *font, * for code points modified by variation selectors. For variation-selector * support, user hb_font_get_variation_glyph() or use hb_font_get_glyph(). * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 1.2.3 **/ @@ -996,7 +1061,8 @@ hb_font_get_nominal_glyph (hb_font_t *font, * @glyph_stride: The stride between successive glyph IDs * * Fetches the nominal glyph IDs for a sequence of Unicode code points. Glyph - * IDs must be returned in a #hb_codepoint_t output parameter. + * IDs must be returned in a #hb_codepoint_t output parameter. Stopes at the + * first unsupported glyph ID. * * Return value: the number of code points processed * @@ -1026,7 +1092,7 @@ hb_font_get_nominal_glyphs (hb_font_t *font, * by the specified variation-selector code point, in the specified * font. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 1.2.3 **/ @@ -1136,7 +1202,7 @@ hb_font_get_glyph_v_advances (hb_font_t* font, * Fetches the (X,Y) coordinates of the origin for a glyph ID * in the specified font, for horizontal text segments. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 **/ @@ -1159,7 +1225,7 @@ hb_font_get_glyph_h_origin (hb_font_t *font, * Fetches the (X,Y) coordinates of the origin for a glyph ID * in the specified font, for vertical text segments. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 **/ @@ -1232,7 +1298,7 @@ hb_font_get_glyph_v_kerning (hb_font_t *font, * Fetches the #hb_glyph_extents_t data for a glyph ID * in the specified font. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 **/ @@ -1255,7 +1321,7 @@ hb_font_get_glyph_extents (hb_font_t *font, * Fetches the (x,y) coordinates of a specified contour-point index * in the specified glyph, within the specified font. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 **/ @@ -1278,7 +1344,10 @@ hb_font_get_glyph_contour_point (hb_font_t *font, * * Fetches the glyph-name string for a glyph ID in the specified @font. * - * Return value: %true if data found, %false otherwise + * According to the OpenType specification, glyph names are limited to 63 + * characters and can only contain (a subset of) ASCII. + * + * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 **/ @@ -1302,7 +1371,7 @@ hb_font_get_glyph_name (hb_font_t *font, * * Note: @len == -1 means the name string is null-terminated. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 **/ @@ -1323,17 +1392,71 @@ hb_font_get_glyph_from_name (hb_font_t *font, * @draw_data: User data to pass to draw callbacks * * Fetches the glyph shape that corresponds to a glyph in the specified @font. - * The shape is returned by way of calls to the callsbacks of the @dfuncs + * The shape is returned by way of calls to the callbacks of the @dfuncs * objects, with @draw_data passed to them. * * Since: 4.0.0 - **/ + * Deprecated: 7.0.0: Use hb_font_draw_glyph() instead + */ void hb_font_get_glyph_shape (hb_font_t *font, hb_codepoint_t glyph, hb_draw_funcs_t *dfuncs, void *draw_data) { - font->get_glyph_shape (glyph, dfuncs, draw_data); + hb_font_draw_glyph (font, glyph, dfuncs, draw_data); +} + +/** + * hb_font_draw_glyph: + * @font: #hb_font_t to work upon + * @glyph: : The glyph ID + * @dfuncs: #hb_draw_funcs_t to draw to + * @draw_data: User data to pass to draw callbacks + * + * Draws the outline that corresponds to a glyph in the specified @font. + * + * The outline is returned by way of calls to the callbacks of the @dfuncs + * objects, with @draw_data passed to them. + * + * Since: 7.0.0 + **/ +void +hb_font_draw_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data) +{ + font->draw_glyph (glyph, dfuncs, draw_data); +} + +/** + * hb_font_paint_glyph: + * @font: #hb_font_t to work upon + * @glyph: The glyph ID + * @pfuncs: #hb_paint_funcs_t to paint with + * @paint_data: User data to pass to paint callbacks + * @palette_index: The index of the font's color palette to use + * @foreground: The foreground color, unpremultipled + * + * Paints the glyph. + * + * The painting instructions are returned by way of calls to + * the callbacks of the @funcs object, with @paint_data passed + * to them. + * + * If the font has color palettes (see hb_ot_color_has_palettes()), + * then @palette_index selects the palette to use. If the font only + * has one palette, this will be 0. + * + * Since: 7.0.0 + */ +void +hb_font_paint_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *pfuncs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground) +{ + font->paint_glyph (glyph, pfuncs, paint_data, palette_index, foreground); } /* A bit higher-level, and with fallback */ @@ -1537,7 +1660,7 @@ hb_font_get_glyph_kerning_for_direction (hb_font_t *font, * Calls the appropriate direction-specific variant (horizontal * or vertical) depending on the value of @direction. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 **/ @@ -1566,7 +1689,7 @@ hb_font_get_glyph_extents_for_origin (hb_font_t *font, * Calls the appropriate direction-specific variant (horizontal * or vertical) depending on the value of @direction. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 **/ @@ -1594,6 +1717,9 @@ hb_font_get_glyph_contour_point_for_origin (hb_font_t *font, * If the glyph ID has no name in @font, a string of the form `gidDDD` is * generated, with `DDD` being the glyph ID. * + * According to the OpenType specification, glyph names are limited to 63 + * characters and can only contain (a subset of) ASCII. + * * Since: 0.9.2 **/ void @@ -1617,7 +1743,7 @@ hb_font_glyph_to_string (hb_font_t *font, * * Note: @len == -1 means the string is null-terminated. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 0.9.2 **/ @@ -1647,8 +1773,13 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 1000, /* x_scale */ 1000, /* y_scale */ - 0., /* slant */ - 0., /* slant_xy; */ + 0.f, /* x_embolden */ + 0.f, /* y_embolden */ + true, /* embolden_in_place */ + 0, /* x_strength */ + 0, /* y_strength */ + 0.f, /* slant */ + 0.f, /* slant_xy; */ 1.f, /* x_multf */ 1.f, /* y_multf */ 1<<16, /* x_mult */ @@ -1658,6 +1789,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 0, /* y_ppem */ 0, /* ptem */ + HB_FONT_NO_VAR_NAMED_INSTANCE, /* instance_index */ 0, /* num_coords */ nullptr, /* coords */ nullptr, /* design_coords */ @@ -1675,6 +1807,7 @@ _hb_font_create (hb_face_t *face) if (unlikely (!face)) face = hb_face_get_empty (); + if (!(font = hb_object_create ())) return hb_font_get_empty (); @@ -1684,8 +1817,10 @@ _hb_font_create (hb_face_t *face) font->klass = hb_font_funcs_get_empty (); font->data.init0 (font); font->x_scale = font->y_scale = face->get_upem (); + font->embolden_in_place = true; font->x_multf = font->y_multf = 1.f; font->x_mult = font->y_mult = 1 << 16; + font->instance_index = HB_FONT_NO_VAR_NAMED_INSTANCE; return font; } @@ -1767,6 +1902,9 @@ hb_font_create_sub_font (hb_font_t *parent) font->x_scale = parent->x_scale; font->y_scale = parent->y_scale; + font->x_embolden = parent->x_embolden; + font->y_embolden = parent->y_embolden; + font->embolden_in_place = parent->embolden_in_place; font->slant = parent->slant; font->x_ppem = parent->x_ppem; font->y_ppem = parent->y_ppem; @@ -1779,8 +1917,8 @@ hb_font_create_sub_font (hb_font_t *parent) float *design_coords = (float *) hb_calloc (num_coords, sizeof (parent->design_coords[0])); if (likely (coords && design_coords)) { - memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0])); - memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0])); + hb_memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0])); + hb_memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0])); _hb_font_adopt_var_coords (font, coords, design_coords, num_coords); } else @@ -1866,7 +2004,7 @@ hb_font_destroy (hb_font_t *font) * * Attaches a user-data key/data pair to the specified font object. * - * Return value: %true if success, %false otherwise + * Return value: `true` if success, `false` otherwise * * Since: 0.9.2 **/ @@ -1896,7 +2034,7 @@ hb_font_set_user_data (hb_font_t *font, * Since: 0.9.2 **/ void * -hb_font_get_user_data (hb_font_t *font, +hb_font_get_user_data (const hb_font_t *font, hb_user_data_key_t *key) { return hb_object_get_user_data (font, key); @@ -1928,7 +2066,7 @@ hb_font_make_immutable (hb_font_t *font) * * Tests whether a font object is immutable. * - * Return value: %true if @font is immutable, %false otherwise + * Return value: `true` if @font is immutable, `false` otherwise * * Since: 0.9.2 **/ @@ -1948,7 +2086,7 @@ hb_font_is_immutable (hb_font_t *font) * * Return value: serial number * - * Since: 4.4.0. + * Since: 4.4.0 **/ unsigned int hb_font_get_serial (hb_font_t *font) @@ -1964,7 +2102,7 @@ hb_font_get_serial (hb_font_t *font) * This has the effect of increasing the serial as returned * by hb_font_get_serial(), which invalidates internal caches. * - * Since: 4.4.0. + * Since: 4.4.0 **/ void hb_font_changed (hb_font_t *font) @@ -2156,6 +2294,31 @@ hb_font_set_funcs_data (hb_font_t *font, * * Sets the horizontal and vertical scale of a font. * + * The font scale is a number related to, but not the same as, + * font size. Typically the client establishes a scale factor + * to be used between the two. For example, 64, or 256, which + * would be the fractional-precision part of the font scale. + * This is necessary because #hb_position_t values are integer + * types and you need to leave room for fractional values + * in there. + * + * For example, to set the font size to 20, with 64 + * levels of fractional precision you would call + * `hb_font_set_scale(font, 20 * 64, 20 * 64)`. + * + * In the example above, even what font size 20 means is up to + * you. It might be 20 pixels, or 20 points, or 20 millimeters. + * HarfBuzz does not care about that. You can set the point + * size of the font using hb_font_set_ptem(), and the pixel + * size using hb_font_set_ppem(). + * + * The choice of scale is yours but needs to be consistent between + * what you set here, and what you expect out of #hb_position_t + * as well has draw / paint API output values. + * + * Fonts default to a scale equal to the UPEM value of their face. + * A font with this setting is sometimes called an "unscaled" font. + * * Since: 0.9.2 **/ void @@ -2201,7 +2364,11 @@ hb_font_get_scale (hb_font_t *font, * @x_ppem: Horizontal ppem value to assign * @y_ppem: Vertical ppem value to assign * - * Sets the horizontal and vertical pixels-per-em (ppem) of a font. + * Sets the horizontal and vertical pixels-per-em (PPEM) of a font. + * + * These values are used for pixel-size-specific adjustment to + * shaping and draw results, though for the most part they are + * unused and can be left unset. * * Since: 0.9.2 **/ @@ -2285,6 +2452,76 @@ hb_font_get_ptem (hb_font_t *font) return font->ptem; } +/** + * hb_font_set_synthetic_bold: + * @font: #hb_font_t to work upon + * @x_embolden: the amount to embolden horizontally + * @y_embolden: the amount to embolden vertically + * @in_place: whether to embolden glyphs in-place + * + * Sets the "synthetic boldness" of a font. + * + * Positive values for @x_embolden / @y_embolden make a font + * bolder, negative values thinner. Typical values are in the + * 0.01 to 0.05 range. The default value is zero. + * + * Synthetic boldness is applied by offsetting the contour + * points of the glyph shape. + * + * Synthetic boldness is applied when rendering a glyph via + * hb_font_draw_glyph(). + * + * If @in_place is `false`, then glyph advance-widths are also + * adjusted, otherwise they are not. The in-place mode is + * useful for simulating [font grading](https://fonts.google.com/knowledge/glossary/grade). + * + * + * Since: 7.0.0 + **/ +void +hb_font_set_synthetic_bold (hb_font_t *font, + float x_embolden, + float y_embolden, + hb_bool_t in_place) +{ + if (hb_object_is_immutable (font)) + return; + + if (font->x_embolden == x_embolden && + font->y_embolden == y_embolden && + font->embolden_in_place == (bool) in_place) + return; + + font->serial++; + + font->x_embolden = x_embolden; + font->y_embolden = y_embolden; + font->embolden_in_place = in_place; + font->mults_changed (); +} + +/** + * hb_font_get_synthetic_bold: + * @font: #hb_font_t to work upon + * @x_embolden: (out): return location for horizontal value + * @y_embolden: (out): return location for vertical value + * @in_place: (out): return location for in-place value + * + * Fetches the "synthetic boldness" parameters of a font. + * + * Since: 7.0.0 + **/ +void +hb_font_get_synthetic_bold (hb_font_t *font, + float *x_embolden, + float *y_embolden, + hb_bool_t *in_place) +{ + if (x_embolden) *x_embolden = font->x_embolden; + if (y_embolden) *y_embolden = font->y_embolden; + if (in_place) *in_place = font->embolden_in_place; +} + /** * hb_font_set_synthetic_slant: * @font: #hb_font_t to work upon @@ -2297,9 +2534,8 @@ hb_font_get_ptem (hb_font_t *font) * HarfBuzz needs to know this value to adjust shaping results, * metrics, and style values to match the slanted rendering. * - * Note: The glyph shape fetched via the - * hb_font_get_glyph_shape() is slanted to reflect this value - * as well. + * Note: The glyph shape fetched via the hb_font_draw_glyph() + * function is slanted to reflect this value as well. * * Note: The slant value is a ratio. For example, a * 20% slant would be represented as a 0.2 value. @@ -2366,7 +2602,7 @@ hb_font_set_variations (hb_font_t *font, font->serial_coords = ++font->serial; - if (!variations_length) + if (!variations_length && font->instance_index == HB_FONT_NO_VAR_NAMED_INSTANCE) { hb_font_set_var_coords_normalized (font, nullptr, 0); return; @@ -2386,19 +2622,30 @@ hb_font_set_variations (hb_font_t *font, return; } + /* Initialize design coords. */ + for (unsigned int i = 0; i < coords_length; i++) + design_coords[i] = axes[i].get_default (); + if (font->instance_index != HB_FONT_NO_VAR_NAMED_INSTANCE) + { + unsigned count = coords_length; + /* This may fail if index is out-of-range; + * That's why we initialize design_coords from fvar above + * unconditionally. */ + hb_ot_var_named_instance_get_design_coords (font->face, font->instance_index, + &count, design_coords); + } + for (unsigned int i = 0; i < variations_length; i++) { const auto tag = variations[i].tag; const auto v = variations[i].value; for (unsigned axis_index = 0; axis_index < coords_length; axis_index++) if (axes[axis_index].axisTag == tag) - { design_coords[axis_index] = v; - normalized[axis_index] = fvar.normalize_axis_value (axis_index, v); - } } font->face->table.avar->map_coords (normalized, coords_length); + hb_ot_var_normalize_coords (font->face, coords_length, design_coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); } @@ -2438,7 +2685,7 @@ hb_font_set_var_coords_design (hb_font_t *font, } if (coords_length) - memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0])); + hb_memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0])); hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized); _hb_font_adopt_var_coords (font, normalized, design_coords, coords_length); @@ -2449,28 +2696,40 @@ hb_font_set_var_coords_design (hb_font_t *font, * @font: a font. * @instance_index: named instance index. * - * Sets design coords of a font from a named instance index. + * Sets design coords of a font from a named-instance index. * * Since: 2.6.0 */ void hb_font_set_var_named_instance (hb_font_t *font, - unsigned instance_index) + unsigned int instance_index) { if (hb_object_is_immutable (font)) return; - font->serial_coords = ++font->serial; + if (font->instance_index == instance_index) + return; - unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr); + font->serial_coords = ++font->serial; - float *coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr; - if (unlikely (coords_length && !coords)) - return; + font->instance_index = instance_index; + hb_font_set_variations (font, nullptr, 0); +} - hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords); - hb_font_set_var_coords_design (font, coords, coords_length); - hb_free (coords); +/** + * hb_font_get_var_named_instance: + * @font: a font. + * + * Returns the currently-set named-instance index of the font. + * + * Return value: Named-instance index or %HB_FONT_NO_VAR_NAMED_INSTANCE. + * + * Since: 7.0.0 + **/ +unsigned int +hb_font_get_var_named_instance (hb_font_t *font) +{ + return font->instance_index; } /** @@ -2514,8 +2773,8 @@ hb_font_set_var_coords_normalized (hb_font_t *font, if (coords_length) { - memcpy (copy, coords, coords_length * sizeof (coords[0])); - memcpy (unmapped, coords, coords_length * sizeof (coords[0])); + hb_memcpy (copy, coords, coords_length * sizeof (coords[0])); + hb_memcpy (unmapped, coords, coords_length * sizeof (coords[0])); } /* Best effort design coords simulation */ @@ -2719,3 +2978,13 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs, trampoline_destroy); } #endif + + +void +hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_shape_func_t func, + void *user_data, + hb_destroy_func_t destroy /* May be NULL. */) +{ + hb_font_funcs_set_draw_glyph_func (ffuncs, func, user_data, destroy); +} diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.h b/src/java.desktop/share/native/libharfbuzz/hb-font.h index a6aeeef4770..77baf74d191 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.h @@ -34,18 +34,10 @@ #include "hb-common.h" #include "hb-face.h" #include "hb-draw.h" +#include "hb-paint.h" HB_BEGIN_DECLS -/** - * hb_font_t: - * - * Data type for holding fonts. - * - */ -typedef struct hb_font_t hb_font_t; - - /* * hb_font_funcs_t */ @@ -86,8 +78,8 @@ hb_font_funcs_set_user_data (hb_font_funcs_t *ffuncs, HB_EXTERN void * -hb_font_funcs_get_user_data (hb_font_funcs_t *ffuncs, - hb_user_data_key_t *key); +hb_font_funcs_get_user_data (const hb_font_funcs_t *ffuncs, + hb_user_data_key_t *key); HB_EXTERN void @@ -97,7 +89,7 @@ HB_EXTERN hb_bool_t hb_font_funcs_is_immutable (hb_font_funcs_t *ffuncs); -/* font and glyph extents */ +/* font extents */ /** * hb_font_extents_t: @@ -126,24 +118,6 @@ typedef struct hb_font_extents_t { hb_position_t reserved1; } hb_font_extents_t; -/** - * hb_glyph_extents_t: - * @x_bearing: Distance from the x-origin to the left extremum of the glyph. - * @y_bearing: Distance from the top extremum of the glyph to the y-origin. - * @width: Distance from the left extremum of the glyph to the right extremum. - * @height: Distance from the top extremum of the glyph to the bottom extremum. - * - * Glyph extent values, measured in font units. - * - * Note that @height is negative, in coordinate systems that grow up. - **/ -typedef struct hb_glyph_extents_t { - hb_position_t x_bearing; - hb_position_t y_bearing; - hb_position_t width; - hb_position_t height; -} hb_glyph_extents_t; - /* func types */ /** @@ -198,7 +172,7 @@ typedef hb_font_get_font_extents_func_t hb_font_get_font_v_extents_func_t; * This method should retrieve the nominal glyph ID for a specified Unicode code * point. Glyph IDs must be returned in a #hb_codepoint_t output parameter. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * **/ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *font_data, @@ -221,7 +195,7 @@ typedef hb_bool_t (*hb_font_get_nominal_glyph_func_t) (hb_font_t *font, void *fo * followed by a specified Variation Selector code point. Glyph IDs must be * returned in a #hb_codepoint_t output parameter. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * **/ typedef hb_bool_t (*hb_font_get_variation_glyph_func_t) (hb_font_t *font, void *font_data, @@ -362,7 +336,7 @@ typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t; * origin for a glyph. Each coordinate must be returned in an #hb_position_t * output parameter. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * **/ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data, @@ -434,7 +408,7 @@ typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t; * This method should retrieve the extents for a specified glyph. Extents must be * returned in an #hb_glyph_extents output parameter. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * **/ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data, @@ -458,7 +432,7 @@ typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *fo * specified contour point in a glyph. Each coordinate must be returned as * an #hb_position_t output parameter. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * **/ typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, void *font_data, @@ -481,7 +455,7 @@ typedef hb_bool_t (*hb_font_get_glyph_contour_point_func_t) (hb_font_t *font, vo * This method should retrieve the glyph name that corresponds to a * glyph ID. The name should be returned in a string output parameter. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * **/ typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_data, @@ -503,7 +477,7 @@ typedef hb_bool_t (*hb_font_get_glyph_name_func_t) (hb_font_t *font, void *font_ * This method should retrieve the glyph ID that corresponds to a glyph-name * string. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * **/ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void *font_data, @@ -523,13 +497,53 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void * * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. * * Since: 4.0.0 - * + * Deprecated: 7.0.0: Use #hb_font_draw_glyph_func_t instead **/ typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data, hb_codepoint_t glyph, hb_draw_funcs_t *draw_funcs, void *draw_data, void *user_data); +/** + * hb_font_draw_glyph_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @draw_funcs: The draw functions to send the shape data to + * @draw_data: The data accompanying the draw functions + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 7.0.0 + * + **/ +typedef void (*hb_font_draw_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data); + +/** + * hb_font_paint_glyph_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @paint_funcs: The paint functions to use + * @paint_data: The data accompanying the paint functions + * @palette_index: The color palette to use + * @foreground: The foreground color + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 7.0.0 + */ +typedef void (*hb_font_paint_glyph_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data); /* func setters */ @@ -796,15 +810,50 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, * @user_data: Data to pass to @func * @destroy: (nullable): The function to call when @user_data is not needed anymore * - * Sets the implementation function for #hb_font_get_glyph_shape_func_t. + * Sets the implementation function for #hb_font_get_glyph_shape_func_t, + * which is the same as #hb_font_draw_glyph_func_t. * * Since: 4.0.0 + * Deprecated: 7.0.0: Use hb_font_funcs_set_draw_glyph_func() instead **/ HB_EXTERN void hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_shape_func_t func, void *user_data, hb_destroy_func_t destroy); +/** + * hb_font_funcs_set_draw_glyph_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets the implementation function for #hb_font_draw_glyph_func_t, + * which is the same as #hb_font_get_glyph_shape_func_t. + * + * Since: 7.0.0 + **/ +HB_EXTERN void +hb_font_funcs_set_draw_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_draw_glyph_func_t func, + void *user_data, hb_destroy_func_t destroy); + +/** + * hb_font_funcs_set_paint_glyph_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is no longer needed + * + * Sets the implementation function for #hb_font_paint_glyph_func_t. + * + * Since: 7.0.0 + */ +HB_EXTERN void +hb_font_funcs_set_paint_glyph_func (hb_font_funcs_t *ffuncs, + hb_font_paint_glyph_func_t func, + void *user_data, hb_destroy_func_t destroy); + /* func dispatch */ HB_EXTERN hb_bool_t @@ -890,6 +939,17 @@ hb_font_get_glyph_shape (hb_font_t *font, hb_codepoint_t glyph, hb_draw_funcs_t *dfuncs, void *draw_data); +HB_EXTERN void +hb_font_draw_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data); + +HB_EXTERN void +hb_font_paint_glyph (hb_font_t *font, + hb_codepoint_t glyph, + hb_paint_funcs_t *pfuncs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground); /* high-level funcs, with fallback */ @@ -993,7 +1053,7 @@ hb_font_set_user_data (hb_font_t *font, HB_EXTERN void * -hb_font_get_user_data (hb_font_t *font, +hb_font_get_user_data (const hb_font_t *font, hb_user_data_key_t *key); HB_EXTERN void @@ -1069,6 +1129,16 @@ hb_font_set_ptem (hb_font_t *font, float ptem); HB_EXTERN float hb_font_get_ptem (hb_font_t *font); +HB_EXTERN void +hb_font_set_synthetic_bold (hb_font_t *font, + float x_embolden, float y_embolden, + hb_bool_t in_place); + +HB_EXTERN void +hb_font_get_synthetic_bold (hb_font_t *font, + float *x_embolden, float *y_embolden, + hb_bool_t *in_place); + HB_EXTERN void hb_font_set_synthetic_slant (hb_font_t *font, float slant); @@ -1098,10 +1168,23 @@ HB_EXTERN const int * hb_font_get_var_coords_normalized (hb_font_t *font, unsigned int *length); +/** + * HB_FONT_NO_VAR_NAMED_INSTANCE: + * + * Constant signifying that a font does not have any + * named-instance index set. This is the default of + * a font. + * + * Since: 7.0.0 + */ +#define HB_FONT_NO_VAR_NAMED_INSTANCE 0xFFFFFFFF + HB_EXTERN void hb_font_set_var_named_instance (hb_font_t *font, - unsigned instance_index); + unsigned int instance_index); +HB_EXTERN unsigned int +hb_font_get_var_named_instance (hb_font_t *font); HB_END_DECLS diff --git a/src/java.desktop/share/native/libharfbuzz/hb-font.hh b/src/java.desktop/share/native/libharfbuzz/hb-font.hh index 3af9d74012a..c3198830cd3 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-font.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-font.hh @@ -40,24 +40,25 @@ */ #define HB_FONT_FUNCS_IMPLEMENT_CALLBACKS \ - HB_FONT_FUNC_IMPLEMENT (font_h_extents) \ - HB_FONT_FUNC_IMPLEMENT (font_v_extents) \ - HB_FONT_FUNC_IMPLEMENT (nominal_glyph) \ - HB_FONT_FUNC_IMPLEMENT (nominal_glyphs) \ - HB_FONT_FUNC_IMPLEMENT (variation_glyph) \ - HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \ - HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \ - HB_FONT_FUNC_IMPLEMENT (glyph_h_advances) \ - HB_FONT_FUNC_IMPLEMENT (glyph_v_advances) \ - HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \ - HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \ - HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \ - HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \ - HB_FONT_FUNC_IMPLEMENT (glyph_extents) \ - HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \ - HB_FONT_FUNC_IMPLEMENT (glyph_name) \ - HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \ - HB_FONT_FUNC_IMPLEMENT (glyph_shape) \ + HB_FONT_FUNC_IMPLEMENT (get_,font_h_extents) \ + HB_FONT_FUNC_IMPLEMENT (get_,font_v_extents) \ + HB_FONT_FUNC_IMPLEMENT (get_,nominal_glyph) \ + HB_FONT_FUNC_IMPLEMENT (get_,nominal_glyphs) \ + HB_FONT_FUNC_IMPLEMENT (get_,variation_glyph) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_advance) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advance) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_advances) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_advances) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_origin) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_origin) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_h_kerning) \ + HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (get_,glyph_v_kerning)) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_extents) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_contour_point) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_name) \ + HB_FONT_FUNC_IMPLEMENT (get_,glyph_from_name) \ + HB_FONT_FUNC_IMPLEMENT (,draw_glyph) \ + HB_FONT_FUNC_IMPLEMENT (,paint_glyph) \ /* ^--- Add new callbacks here */ struct hb_font_funcs_t @@ -65,13 +66,13 @@ struct hb_font_funcs_t hb_object_header_t header; struct { -#define HB_FONT_FUNC_IMPLEMENT(name) void *name; +#define HB_FONT_FUNC_IMPLEMENT(get_,name) void *name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } *user_data; struct { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_destroy_func_t name; +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_destroy_func_t name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } *destroy; @@ -79,12 +80,12 @@ struct hb_font_funcs_t /* Don't access these directly. Call font->get_*() instead. */ union get_t { struct get_funcs_t { -#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_func_t name; +#define HB_FONT_FUNC_IMPLEMENT(get_,name) hb_font_##get_##name##_func_t name; HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT } f; void (*array[0 -#define HB_FONT_FUNC_IMPLEMENT(name) +1 +#define HB_FONT_FUNC_IMPLEMENT(get_,name) +1 HB_FONT_FUNCS_IMPLEMENT_CALLBACKS #undef HB_FONT_FUNC_IMPLEMENT ]) (); @@ -112,8 +113,16 @@ struct hb_font_t int32_t x_scale; int32_t y_scale; + + float x_embolden; + float y_embolden; + bool embolden_in_place; + int32_t x_strength; /* x_embolden, in scaled units. */ + int32_t y_strength; /* y_embolden, in scaled units. */ + float slant; float slant_xy; + float x_multf; float y_multf; int64_t x_mult; @@ -125,6 +134,7 @@ struct hb_font_t float ptem; /* Font variation coordinates. */ + unsigned int instance_index; unsigned int num_coords; int *coords; float *design_coords; @@ -179,6 +189,42 @@ struct hb_font_t *y = parent_scale_y_position (*y); } + void scale_glyph_extents (hb_glyph_extents_t *extents) + { + float x1 = em_fscale_x (extents->x_bearing); + float y1 = em_fscale_y (extents->y_bearing); + float x2 = em_fscale_x (extents->x_bearing + extents->width); + float y2 = em_fscale_y (extents->y_bearing + extents->height); + + /* Apply slant. */ + if (slant_xy) + { + x1 += hb_min (y1 * slant_xy, y2 * slant_xy); + x2 += hb_max (y1 * slant_xy, y2 * slant_xy); + } + + extents->x_bearing = floorf (x1); + extents->y_bearing = floorf (y1); + extents->width = ceilf (x2) - extents->x_bearing; + extents->height = ceilf (y2) - extents->y_bearing; + + if (x_strength || y_strength) + { + /* Y */ + int y_shift = y_strength; + if (y_scale < 0) y_shift = -y_shift; + extents->y_bearing += y_shift; + extents->height -= y_shift; + + /* X */ + int x_shift = x_strength; + if (x_scale < 0) x_shift = -x_shift; + if (embolden_in_place) + extents->x_bearing -= x_shift / 2; + extents->width += x_shift; + } + } + /* Public getters */ @@ -186,7 +232,7 @@ struct hb_font_t HB_INTERNAL bool has_func_set (unsigned int i); /* has_* ... */ -#define HB_FONT_FUNC_IMPLEMENT(name) \ +#define HB_FONT_FUNC_IMPLEMENT(get_,name) \ bool \ has_##name##_func () \ { \ @@ -206,14 +252,14 @@ struct hb_font_t hb_bool_t get_font_h_extents (hb_font_extents_t *extents) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return klass->get.f.font_h_extents (this, user_data, extents, !klass->user_data ? nullptr : klass->user_data->font_h_extents); } hb_bool_t get_font_v_extents (hb_font_extents_t *extents) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return klass->get.f.font_v_extents (this, user_data, extents, !klass->user_data ? nullptr : klass->user_data->font_v_extents); @@ -342,7 +388,7 @@ struct hb_font_t hb_bool_t get_glyph_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) { - memset (extents, 0, sizeof (*extents)); + hb_memset (extents, 0, sizeof (*extents)); return klass->get.f.glyph_extents (this, user_data, glyph, extents, @@ -380,15 +426,26 @@ struct hb_font_t !klass->user_data ? nullptr : klass->user_data->glyph_from_name); } - void get_glyph_shape (hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data) + void draw_glyph (hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data) { - klass->get.f.glyph_shape (this, user_data, - glyph, - draw_funcs, draw_data, - !klass->user_data ? nullptr : klass->user_data->glyph_shape); + klass->get.f.draw_glyph (this, user_data, + glyph, + draw_funcs, draw_data, + !klass->user_data ? nullptr : klass->user_data->draw_glyph); } + void paint_glyph (hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette, + hb_color_t foreground) + { + klass->get.f.paint_glyph (this, user_data, + glyph, + paint_funcs, paint_data, + palette, foreground, + !klass->user_data ? nullptr : klass->user_data->paint_glyph); + } /* A bit higher-level, and with fallback */ @@ -632,12 +689,17 @@ struct hb_font_t void mults_changed () { float upem = face->get_upem (); + x_multf = x_scale / upem; y_multf = y_scale / upem; bool x_neg = x_scale < 0; x_mult = (x_neg ? -((int64_t) -x_scale << 16) : ((int64_t) x_scale << 16)) / upem; bool y_neg = y_scale < 0; y_mult = (y_neg ? -((int64_t) -y_scale << 16) : ((int64_t) y_scale << 16)) / upem; + + x_strength = fabsf (roundf (x_scale * x_embolden)); + y_strength = fabsf (roundf (y_scale * y_embolden)); + slant_xy = y_scale ? slant * x_scale / y_scale : 0.f; data.fini (); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc index 291d1e8d70c..93ef3b02d47 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ft.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ft.cc @@ -33,17 +33,22 @@ #include "hb-ft.h" +#include "hb-cache.hh" #include "hb-draw.hh" #include "hb-font.hh" #include "hb-machinery.hh" -#include "hb-cache.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-shaper-arabic-pua.hh" +#include "hb-paint.hh" #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H #include FT_OUTLINE_H #include FT_TRUETYPE_TABLES_H +#include FT_SYNTHESIS_H +#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 +#include FT_COLOR_H +#endif /** @@ -80,16 +85,19 @@ */ +using hb_ft_advance_cache_t = hb_cache_t<16, 8, 8, false>; + struct hb_ft_font_t { int load_flags; bool symbol; /* Whether selected cmap is symbol cmap. */ bool unref; /* Whether to destroy ft_face when done. */ + bool transform; /* Whether to apply FT_Face's transform. */ - mutable hb_mutex_t lock; + mutable hb_mutex_t lock; /* Protects members below. */ FT_Face ft_face; mutable unsigned cached_serial; - mutable hb_advance_cache_t advance_cache; + mutable hb_ft_advance_cache_t advance_cache; }; static hb_ft_font_t * @@ -122,8 +130,6 @@ _hb_ft_font_destroy (void *data) { hb_ft_font_t *ft_font = (hb_ft_font_t *) data; - ft_font->advance_cache.fini (); - if (ft_font->unref) _hb_ft_face_destroy (ft_font->ft_face); @@ -136,32 +142,59 @@ _hb_ft_font_destroy (void *data) /* hb_font changed, update FT_Face. */ static void _hb_ft_hb_font_changed (hb_font_t *font, FT_Face ft_face) { + hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data; + + float x_mult = 1.f, y_mult = 1.f; + + if (font->x_scale < 0) x_mult = -x_mult; + if (font->y_scale < 0) y_mult = -y_mult; - FT_Set_Char_Size (ft_face, - abs (font->x_scale), abs (font->y_scale), - 0, 0); + if (FT_Set_Char_Size (ft_face, + abs (font->x_scale), abs (font->y_scale), + 0, 0 #if 0 font->x_ppem * 72 * 64 / font->x_scale, - font->y_ppem * 72 * 64 / font->y_scale); + font->y_ppem * 72 * 64 / font->y_scale #endif - if (font->x_scale < 0 || font->y_scale < 0) + ) && ft_face->num_fixed_sizes) { - FT_Matrix matrix = { font->x_scale < 0 ? -1 : +1, 0, - 0, font->y_scale < 0 ? -1 : +1}; +#ifdef HAVE_FT_GET_TRANSFORM + /* Bitmap font, eg. bitmap color emoji. */ + /* Pick largest size? */ + int x_scale = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].x_ppem; + int y_scale = ft_face->available_sizes[ft_face->num_fixed_sizes - 1].y_ppem; + FT_Set_Char_Size (ft_face, + x_scale, y_scale, + 0, 0); + + /* This contains the sign that was previously in x_mult/y_mult. */ + x_mult = (float) font->x_scale / x_scale; + y_mult = (float) font->y_scale / y_scale; +#endif + } + else + { /* Shrug */ } + + + if (x_mult != 1.f || y_mult != 1.f) + { + FT_Matrix matrix = { (int) roundf (x_mult * (1<<16)), 0, + 0, (int) roundf (y_mult * (1<<16))}; FT_Set_Transform (ft_face, &matrix, nullptr); + ft_font->transform = true; } #if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR) unsigned int num_coords; - const int *coords = hb_font_get_var_coords_normalized (font, &num_coords); + const float *coords = hb_font_get_var_coords_design (font, &num_coords); if (num_coords) { FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed)); if (ft_coords) { for (unsigned int i = 0; i < num_coords; i++) - ft_coords[i] = coords[i] * 4; - FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords); + ft_coords[i] = coords[i] * 65536.f; + FT_Set_Var_Design_Coordinates (ft_face, num_coords, ft_coords); hb_free (ft_coords); } } @@ -194,6 +227,9 @@ _hb_ft_hb_font_check_changed (hb_font_t *font, * For more information, see * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx * + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). + * * Since: 1.0.5 **/ void @@ -219,7 +255,10 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags) * For more information, see * https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx * - * Return value: FT_Load_Glyph flags found + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). + * + * Return value: FT_Load_Glyph flags found, or 0 * * Since: 1.0.5 **/ @@ -241,7 +280,10 @@ hb_ft_font_get_load_flags (hb_font_t *font) * Fetches the FT_Face associated with the specified #hb_font_t * font object. * - * Return value: (nullable): the FT_Face found or %NULL + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). + * + * Return value: (nullable): the FT_Face found or `NULL` * * Since: 0.9.2 **/ @@ -260,10 +302,15 @@ hb_ft_font_get_face (hb_font_t *font) * hb_ft_font_lock_face: (skip) * @font: #hb_font_t to work upon * - * Gets the FT_Face associated with @font, This face will be kept around until - * you call hb_ft_font_unlock_face(). + * Gets the FT_Face associated with @font. + * + * This face will be kept around and access to the FT_Face object + * from other HarfBuzz API wil be blocked until you call hb_ft_font_unlock_face(). * - * Return value: (nullable): the FT_Face associated with @font or %NULL + * This function works with #hb_font_t objects created by + * hb_ft_font_create() or hb_ft_font_create_referenced(). + * + * Return value: (nullable) (transfer none): the FT_Face associated with @font or `NULL` * Since: 2.6.5 **/ FT_Face @@ -280,7 +327,7 @@ hb_ft_font_lock_face (hb_font_t *font) } /** - * hb_ft_font_unlock_face: + * hb_ft_font_unlock_face: (skip) * @font: #hb_font_t to work upon * * Releases an FT_Face previously obtained with hb_ft_font_lock_face(). @@ -401,10 +448,24 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_position_t *orig_first_advance = first_advance; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; int load_flags = ft_font->load_flags; - int mult = font->x_scale < 0 ? -1 : +1; + float x_mult; +#ifdef HAVE_FT_GET_TRANSFORM + if (ft_font->transform) + { + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + x_mult *= font->x_scale < 0 ? -1 : +1; + } + else +#endif + { + x_mult = font->x_scale < 0 ? -1 : +1; + } for (unsigned int i = 0; i < count; i++) { @@ -417,13 +478,29 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, else { FT_Get_Advance (ft_face, glyph, load_flags, &v); + /* Work around bug that FreeType seems to return negative advance + * for variable-set fonts if x_scale is negative! */ + v = abs (v); + v = (int) (v * x_mult + (1<<9)) >> 10; ft_font->advance_cache.set (glyph, v); } - *first_advance = (v * mult + (1<<9)) >> 10; + *first_advance = v; first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } + + if (font->x_strength && !font->embolden_in_place) + { + /* Emboldening. */ + hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength; + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? x_strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } #ifndef HB_NO_VERTICAL @@ -436,17 +513,31 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Fixed v; + float y_mult; +#ifdef HAVE_FT_GET_TRANSFORM + if (ft_font->transform) + { + FT_Matrix matrix; + FT_Get_Transform (ft_font->ft_face, &matrix, nullptr); + y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; + } + else +#endif + { + y_mult = font->y_scale < 0 ? -1 : +1; + } if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v))) return 0; - if (font->y_scale < 0) - v = -v; + v = (int) (y_mult * v); /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates * have a Y growing upward. Hence the extra negation. */ - return (-v + (1<<9)) >> 10; + hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; + return ((-v + (1<<9)) >> 10) + (font->embolden_in_place ? 0 : y_strength); } #endif @@ -462,6 +553,23 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + float x_mult, y_mult; +#ifdef HAVE_FT_GET_TRANSFORM + if (ft_font->transform) + { + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + x_mult *= font->x_scale < 0 ? -1 : +1; + y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; + } + else +#endif + { + x_mult = font->x_scale < 0 ? -1 : +1; + y_mult = font->y_scale < 0 ? -1 : +1; + } if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; @@ -471,10 +579,8 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); - if (font->x_scale < 0) - *x = -*x; - if (font->y_scale < 0) - *y = -*y; + *x = (hb_position_t) (x_mult * *x); + *y = (hb_position_t) (y_mult * *y); return true; } @@ -510,24 +616,63 @@ hb_ft_get_glyph_extents (hb_font_t *font, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + float x_mult, y_mult; + float slant_xy = font->slant_xy; +#ifdef HAVE_FT_GET_TRANSFORM + if (ft_font->transform) + { + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + x_mult = sqrtf ((float)matrix.xx * matrix.xx + (float)matrix.xy * matrix.xy) / 65536.f; + x_mult *= font->x_scale < 0 ? -1 : +1; + y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; + } + else +#endif + { + x_mult = font->x_scale < 0 ? -1 : +1; + y_mult = font->y_scale < 0 ? -1 : +1; + } if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags))) return false; - extents->x_bearing = ft_face->glyph->metrics.horiBearingX; - extents->y_bearing = ft_face->glyph->metrics.horiBearingY; - extents->width = ft_face->glyph->metrics.width; - extents->height = -ft_face->glyph->metrics.height; - if (font->x_scale < 0) + /* Copied from hb_font_t::scale_glyph_extents. */ + + float x1 = x_mult * ft_face->glyph->metrics.horiBearingX; + float y1 = y_mult * ft_face->glyph->metrics.horiBearingY; + float x2 = x1 + x_mult * ft_face->glyph->metrics.width; + float y2 = y1 + y_mult * -ft_face->glyph->metrics.height; + + /* Apply slant. */ + if (slant_xy) { - extents->x_bearing = -extents->x_bearing; - extents->width = -extents->width; + x1 += hb_min (y1 * slant_xy, y2 * slant_xy); + x2 += hb_max (y1 * slant_xy, y2 * slant_xy); } - if (font->y_scale < 0) + + extents->x_bearing = floorf (x1); + extents->y_bearing = floorf (y1); + extents->width = ceilf (x2) - extents->x_bearing; + extents->height = ceilf (y2) - extents->y_bearing; + + if (font->x_strength || font->y_strength) { - extents->y_bearing = -extents->y_bearing; - extents->height = -extents->height; + /* Y */ + int y_shift = font->y_strength; + if (font->y_scale < 0) y_shift = -y_shift; + extents->y_bearing += y_shift; + extents->height -= y_shift; + + /* X */ + int x_shift = font->x_strength; + if (font->x_scale < 0) x_shift = -x_shift; + if (font->embolden_in_place) + extents->x_bearing -= x_shift / 2; + extents->width += x_shift; } + return true; } @@ -620,16 +765,39 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; + float y_mult; +#ifdef HAVE_FT_GET_TRANSFORM + if (ft_font->transform) + { + FT_Matrix matrix; + FT_Get_Transform (ft_face, &matrix, nullptr); + y_mult = sqrtf ((float)matrix.yx * matrix.yx + (float)matrix.yy * matrix.yy) / 65536.f; + y_mult *= font->y_scale < 0 ? -1 : +1; + } + else +#endif + { + y_mult = font->y_scale < 0 ? -1 : +1; + } - metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale); - metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale); - metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender); - if (font->y_scale < 0) + if (ft_face->units_per_EM != 0) { - metrics->ascender = -metrics->ascender; - metrics->descender = -metrics->descender; - metrics->line_gap = -metrics->line_gap; + metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale); + metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale); + metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender); } + else + { + /* Bitmap-only font, eg. color bitmap font. */ + metrics->ascender = ft_face->size->metrics.ascender; + metrics->descender = ft_face->size->metrics.descender; + metrics->line_gap = ft_face->size->metrics.height - (metrics->ascender - metrics->descender); + } + + metrics->ascender = (hb_position_t) (y_mult * (metrics->ascender + font->y_strength)); + metrics->descender = (hb_position_t) (y_mult * metrics->descender); + metrics->line_gap = (hb_position_t) (y_mult * metrics->line_gap); + return true; } @@ -637,16 +805,18 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, static int _hb_ft_move_to (const FT_Vector *to, - hb_draw_session_t *drawing) + void *arg) { + hb_draw_session_t *drawing = (hb_draw_session_t *) arg; drawing->move_to (to->x, to->y); return FT_Err_Ok; } static int _hb_ft_line_to (const FT_Vector *to, - hb_draw_session_t *drawing) + void *arg) { + hb_draw_session_t *drawing = (hb_draw_session_t *) arg; drawing->line_to (to->x, to->y); return FT_Err_Ok; } @@ -654,8 +824,9 @@ _hb_ft_line_to (const FT_Vector *to, static int _hb_ft_conic_to (const FT_Vector *control, const FT_Vector *to, - hb_draw_session_t *drawing) + void *arg) { + hb_draw_session_t *drawing = (hb_draw_session_t *) arg; drawing->quadratic_to (control->x, control->y, to->x, to->y); return FT_Err_Ok; @@ -665,8 +836,9 @@ static int _hb_ft_cubic_to (const FT_Vector *control1, const FT_Vector *control2, const FT_Vector *to, - hb_draw_session_t *drawing) + void *arg) { + hb_draw_session_t *drawing = (hb_draw_session_t *) arg; drawing->cubic_to (control1->x, control1->y, control2->x, control2->y, to->x, to->y); @@ -674,18 +846,16 @@ _hb_ft_cubic_to (const FT_Vector *control1, } static void -hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED, - void *font_data, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data, - void *user_data HB_UNUSED) +hb_ft_draw_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data HB_UNUSED) { const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; hb_lock_t lock (ft_font->lock); FT_Face ft_face = ft_font->ft_face; - _hb_ft_hb_font_check_changed (font, ft_font); - if (unlikely (FT_Load_Glyph (ft_face, glyph, FT_LOAD_NO_BITMAP | ft_font->load_flags))) return; @@ -694,22 +864,139 @@ hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED, return; const FT_Outline_Funcs outline_funcs = { - (FT_Outline_MoveToFunc) _hb_ft_move_to, - (FT_Outline_LineToFunc) _hb_ft_line_to, - (FT_Outline_ConicToFunc) _hb_ft_conic_to, - (FT_Outline_CubicToFunc) _hb_ft_cubic_to, + _hb_ft_move_to, + _hb_ft_line_to, + _hb_ft_conic_to, + _hb_ft_cubic_to, 0, /* shift */ 0, /* delta */ }; hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); + /* Embolden */ + if (font->x_strength || font->y_strength) + { + FT_Outline_EmboldenXY (&ft_face->glyph->outline, font->x_strength, font->y_strength); + + int x_shift = 0; + int y_shift = 0; + if (font->embolden_in_place) + { + /* Undo the FreeType shift. */ + x_shift = -font->x_strength / 2; + y_shift = 0; + if (font->y_scale < 0) y_shift = -font->y_strength; + } + else + { + /* FreeType applied things in the wrong direction for negative scale; fix up. */ + if (font->x_scale < 0) x_shift = -font->x_strength; + if (font->y_scale < 0) y_shift = -font->y_strength; + } + if (x_shift || y_shift) + { + auto &outline = ft_face->glyph->outline; + for (auto &point : hb_iter (outline.points, outline.contours[outline.n_contours - 1] + 1)) + { + point.x += x_shift; + point.y += y_shift; + } + } + } + + FT_Outline_Decompose (&ft_face->glyph->outline, &outline_funcs, &draw_session); } #endif +#ifndef HB_NO_PAINT +#if (FREETYPE_MAJOR*10000 + FREETYPE_MINOR*100 + FREETYPE_PATCH) >= 21300 + +#include "hb-ft-colr.hh" + +static void +hb_ft_paint_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t gid, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette_index, + hb_color_t foreground, + void *user_data) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); + FT_Face ft_face = ft_font->ft_face; + + /* We release the lock before calling into glyph callbacks, such that + * eg. draw API can call back into the face.*/ + + if (unlikely (FT_Load_Glyph (ft_face, gid, + ft_font->load_flags | FT_LOAD_COLOR))) + return; + + if (ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE) + { + if (hb_ft_paint_glyph_colr (font, font_data, gid, + paint_funcs, paint_data, + palette_index, foreground, + user_data)) + return; + + /* Simple outline. */ + ft_font->lock.unlock (); + paint_funcs->push_clip_glyph (paint_data, gid, font); + ft_font->lock.lock (); + paint_funcs->color (paint_data, true, foreground); + paint_funcs->pop_clip (paint_data); + + return; + } + + auto *glyph = ft_face->glyph; + if (glyph->format == FT_GLYPH_FORMAT_BITMAP) + { + auto &bitmap = glyph->bitmap; + if (bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) + { + if (bitmap.pitch != (signed) bitmap.width * 4) + return; + + ft_font->lock.unlock (); + + hb_blob_t *blob = hb_blob_create ((const char *) bitmap.buffer, + bitmap.pitch * bitmap.rows, + HB_MEMORY_MODE_DUPLICATE, + nullptr, nullptr); + + hb_glyph_extents_t extents; + if (!hb_font_get_glyph_extents (font, gid, &extents)) + goto out; + + if (!paint_funcs->image (paint_data, + blob, + bitmap.width, + bitmap.rows, + HB_PAINT_IMAGE_FORMAT_BGRA, + font->slant_xy, + &extents)) + { + /* TODO Try a forced outline load and paint? */ + } + + out: + hb_blob_destroy (blob); + ft_font->lock.lock (); + } + + return; + } +} +#endif +#endif + static inline void free_static_ft_funcs (); @@ -743,7 +1030,13 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t= 21300 + hb_font_funcs_set_paint_glyph_func (funcs, hb_ft_paint_glyph, nullptr, nullptr); +#endif #endif hb_font_funcs_make_immutable (funcs); @@ -818,6 +1111,10 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data * * Creates an #hb_face_t face object from the specified FT_Face. * + * Note that this is using the FT_Face object just to get at the underlying + * font data, and fonts created from the returned #hb_face_t will use the native + * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. + * * This variant of the function does not provide any life-cycle management. * * Most client programs should use hb_ft_face_create_referenced() @@ -862,6 +1159,10 @@ hb_ft_face_create (FT_Face ft_face, * * Creates an #hb_face_t face object from the specified FT_Face. * + * Note that this is using the FT_Face object just to get at the underlying + * font data, and fonts created from the returned #hb_face_t will use the native + * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. + * * This is the preferred variant of the hb_ft_face_create* * function family, because it calls FT_Reference_Face() on @ft_face, * ensuring that @ft_face remains alive as long as the resulting @@ -882,8 +1183,9 @@ hb_ft_face_create_referenced (FT_Face ft_face) } static void -hb_ft_face_finalize (FT_Face ft_face) +hb_ft_face_finalize (void *arg) { + FT_Face ft_face = (FT_Face) arg; hb_face_destroy ((hb_face_t *) ft_face->generic.data); } @@ -893,6 +1195,10 @@ hb_ft_face_finalize (FT_Face ft_face) * * Creates an #hb_face_t face object from the specified FT_Face. * + * Note that this is using the FT_Face object just to get at the underlying + * font data, and fonts created from the returned #hb_face_t will use the native + * HarfBuzz font implementation, unless you call hb_ft_font_set_funcs() on them. + * * This variant of the function caches the newly created #hb_face_t * face object, using the @generic pointer of @ft_face. Subsequent function * calls that are passed the same @ft_face parameter will have the same @@ -915,7 +1221,7 @@ hb_ft_face_create_cached (FT_Face ft_face) ft_face->generic.finalizer (ft_face); ft_face->generic.data = hb_ft_face_create (ft_face, nullptr); - ft_face->generic.finalizer = (FT_Generic_Finalizer) hb_ft_face_finalize; + ft_face->generic.finalizer = hb_ft_face_finalize; } return hb_face_reference ((hb_face_t *) ft_face->generic.data); @@ -1028,6 +1334,9 @@ hb_ft_font_changed (hb_font_t *font) #endif } #endif + + ft_font->advance_cache.clear (); + ft_font->cached_serial = font->serial; } /** @@ -1121,8 +1430,9 @@ get_ft_library () } static void -_release_blob (FT_Face ft_face) +_release_blob (void *arg) { + FT_Face ft_face = (FT_Face) arg; hb_blob_destroy ((hb_blob_t *) ft_face->generic.data); } @@ -1139,10 +1449,14 @@ _release_blob (FT_Face ft_face) * created with hb_face_create(), and therefore was not * initially configured to use FreeType font functions. * - * An #hb_face_t face object created with hb_ft_face_create() + * An #hb_font_t object created with hb_ft_font_create() * is preconfigured for FreeType font functions and does not * require this function to be used. * + * Note that if you modify the underlying #hb_font_t after + * calling this function, you need to call hb_ft_hb_font_changed() + * to update the underlying FT_Face. + * * Note: Internally, this function creates an FT_Face. * * @@ -1173,14 +1487,14 @@ hb_ft_font_set_funcs (hb_font_t *font) if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL)) FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); - _hb_ft_hb_font_changed (font, ft_face); ft_face->generic.data = blob; - ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob; + ft_face->generic.finalizer = _release_blob; _hb_ft_font_set_funcs (font, ft_face, true); hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING); -} + _hb_ft_hb_font_changed (font, ft_face); +} #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh index ff7a4c75895..bcd4eb8ebc4 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-iter.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-iter.hh @@ -73,8 +73,10 @@ struct hb_iter_t /* Operators. */ iter_t iter () const { return *thiz(); } iter_t operator + () const { return *thiz(); } - iter_t begin () const { return *thiz(); } - iter_t end () const { return thiz()->__end__ (); } + iter_t _begin () const { return *thiz(); } + iter_t begin () const { return _begin (); } + iter_t _end () const { return thiz()->__end__ (); } + iter_t end () const { return _end (); } explicit operator bool () const { return thiz()->__more__ (); } unsigned len () const { return thiz()->__len__ (); } /* The following can only be enabled if item_t is reference type. Otherwise @@ -118,7 +120,9 @@ struct hb_iter_t #define HB_ITER_USING(Name) \ using item_t = typename Name::item_t; \ + using Name::_begin; \ using Name::begin; \ + using Name::_end; \ using Name::end; \ using Name::get_item_size; \ using Name::is_iterator; \ @@ -168,10 +172,16 @@ struct HB_FUNCOBJ (hb_iter); struct { - template unsigned - operator () (T&& c) const - { return c.len (); } + template auto + impl (T&& c, hb_priority<1>) const HB_RETURN (unsigned, c.len ()) + + template auto + impl (T&& c, hb_priority<0>) const HB_RETURN (unsigned, c.len) + + public: + template auto + operator () (T&& c) const HB_RETURN (unsigned, impl (std::forward (c), hb_prioritize)) } HB_FUNCOBJ (hb_len); @@ -253,6 +263,8 @@ struct hb_is_iterator_of }; #define hb_is_iterator_of(Iter, Item) hb_is_iterator_of::value #define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t) +#define hb_is_sorted_iterator_of(Iter, Item) (hb_is_iterator_of::value && Iter::is_sorted_iterator) +#define hb_is_sorted_iterator(Iter) hb_is_sorted_iterator_of (Iter, typename Iter::item_t) /* hb_is_iterable() */ @@ -375,7 +387,7 @@ struct hb_map_iter_t : void __forward__ (unsigned n) { it += n; } void __prev__ () { --it; } void __rewind__ (unsigned n) { it -= n; } - hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); } + hb_map_iter_t __end__ () const { return hb_map_iter_t (it._end (), f); } bool operator != (const hb_map_iter_t& o) const { return it != o.it; } @@ -438,7 +450,7 @@ struct hb_filter_iter_t : bool __more__ () const { return bool (it); } void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); } void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); } - hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); } + hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it._end (), p, f); } bool operator != (const hb_filter_iter_t& o) const { return it != o.it; } @@ -551,7 +563,7 @@ struct hb_zip_iter_t : void __forward__ (unsigned n) { a += n; b += n; } void __prev__ () { --a; --b; } void __rewind__ (unsigned n) { a -= n; b -= n; } - hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); } + hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a._end (), b._end ()); } /* Note, we should stop if ANY of the iters reaches end. As such two compare * unequal if both items are unequal, NOT if either is unequal. */ bool operator != (const hb_zip_iter_t& o) const @@ -635,7 +647,7 @@ struct hb_concat_iter_t : } } - hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a.end (), b.end ()); } + hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a._end (), b._end ()); } bool operator != (const hb_concat_iter_t& o) const { return a != o.a diff --git a/src/java.desktop/share/native/libharfbuzz/hb-limits.hh b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh new file mode 100644 index 00000000000..0f60e9e2101 --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-limits.hh @@ -0,0 +1,109 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_LIMITS_HH +#define HB_LIMITS_HH + +#include "hb.hh" + + +#ifndef HB_BUFFER_MAX_LEN_FACTOR +#define HB_BUFFER_MAX_LEN_FACTOR 64 +#endif +#ifndef HB_BUFFER_MAX_LEN_MIN +#define HB_BUFFER_MAX_LEN_MIN 16384 +#endif +#ifndef HB_BUFFER_MAX_LEN_DEFAULT +#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */ +#endif + +#ifndef HB_BUFFER_MAX_OPS_FACTOR +#define HB_BUFFER_MAX_OPS_FACTOR 1024 +#endif +#ifndef HB_BUFFER_MAX_OPS_MIN +#define HB_BUFFER_MAX_OPS_MIN 16384 +#endif +#ifndef HB_BUFFER_MAX_OPS_DEFAULT +#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */ +#endif + + +#ifndef HB_MAX_NESTING_LEVEL +#define HB_MAX_NESTING_LEVEL 64 +#endif + + +#ifndef HB_MAX_CONTEXT_LENGTH +#define HB_MAX_CONTEXT_LENGTH 64 +#endif + +#ifndef HB_CLOSURE_MAX_STAGES +/* + * The maximum number of times a lookup can be applied during shaping. + * Used to limit the number of iterations of the closure algorithm. + * This must be larger than the number of times add_gsub_pause() is + * called in a collect_features call of any shaper. + */ +#define HB_CLOSURE_MAX_STAGES 12 +#endif + +#ifndef HB_MAX_SCRIPTS +#define HB_MAX_SCRIPTS 500 +#endif + +#ifndef HB_MAX_LANGSYS +#define HB_MAX_LANGSYS 2000 +#endif + +#ifndef HB_MAX_LANGSYS_FEATURE_COUNT +#define HB_MAX_LANGSYS_FEATURE_COUNT 50000 +#endif + +#ifndef HB_MAX_FEATURE_INDICES +#define HB_MAX_FEATURE_INDICES 1500 +#endif + +#ifndef HB_MAX_LOOKUP_VISIT_COUNT +#define HB_MAX_LOOKUP_VISIT_COUNT 35000 +#endif + + +#ifndef HB_GLYF_MAX_POINTS +#define HB_GLYF_MAX_POINTS 20000 +#endif + +#ifndef HB_GLYF_MAX_EDGE_COUNT +#define HB_GLYF_MAX_EDGE_COUNT 1024 +#endif + +#ifndef HB_CFF_MAX_OPS +#define HB_CFF_MAX_OPS 10000 +#endif + +#ifndef HB_COLRV1_MAX_EDGE_COUNT +#define HB_COLRV1_MAX_EDGE_COUNT 1024 +#endif + + +#endif /* HB_LIMITS_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh index 5938a25504a..3a048fc1242 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-machinery.hh @@ -34,7 +34,6 @@ #include "hb-dispatch.hh" #include "hb-sanitize.hh" -#include "hb-serialize.hh" /* @@ -136,6 +135,13 @@ static inline Type& StructAfter(TObject &X) /* * Lazy loaders. + * + * The lazy-loaders are thread-safe pointer-like objects that create their + * instead on-demand. They also support access to a "data" object that is + * necessary for creating their instance. The data object, if specified, + * is accessed via pointer math, located at a location before the position + * of the loader itself. This avoids having to store a pointer to data + * for every lazy-loader. Multiple lazy-loaders can access the same data. */ template @@ -176,12 +182,12 @@ struct hb_lazy_loader_t : hb_data_wrapper_t void init0 () {} /* Init, when memory is already set to 0. No-op for us. */ void init () { instance.set_relaxed (nullptr); } - void fini () { do_destroy (instance.get ()); init (); } + void fini () { do_destroy (instance.get_acquire ()); init (); } void free_instance () { retry: - Stored *p = instance.get (); + Stored *p = instance.get_acquire (); if (unlikely (p && !cmpexch (p, nullptr))) goto retry; do_destroy (p); @@ -203,7 +209,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t Stored * get_stored () const { retry: - Stored *p = this->instance.get (); + Stored *p = this->instance.get_acquire (); if (unlikely (!p)) { if (unlikely (this->is_inert ())) @@ -228,7 +234,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t bool cmpexch (Stored *current, Stored *value) const { - /* This *must* be called when there are no other threads accessing. */ + /* This function can only be safely called directly if no + * other thread is accessing. */ return this->instance.cmpexch (current, value); } @@ -261,7 +268,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t hb_free (p); } -// private: + private: /* Must only have one pointer. */ hb_atomic_ptr_t instance; }; @@ -283,7 +290,7 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_t (face); } static void destroy (hb_blob_t *p) { hb_blob_destroy (p); } @@ -297,22 +304,22 @@ struct hb_table_lazy_loader_t : hb_lazy_loader_tget_stored (); } }; -template -struct hb_font_funcs_lazy_loader_t : hb_lazy_loader_t -{ - static void destroy (hb_font_funcs_t *p) - { hb_font_funcs_destroy (p); } - static const hb_font_funcs_t *get_null () - { return hb_font_funcs_get_empty (); } -}; -template -struct hb_unicode_funcs_lazy_loader_t : hb_lazy_loader_t -{ - static void destroy (hb_unicode_funcs_t *p) - { hb_unicode_funcs_destroy (p); } - static const hb_unicode_funcs_t *get_null () - { return hb_unicode_funcs_get_empty (); } -}; +#define HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T(Type) \ + template \ + struct hb_##Type##_funcs_lazy_loader_t : hb_lazy_loader_t \ + { \ + static void destroy (hb_##Type##_funcs_t *p) \ + { hb_##Type##_funcs_destroy (p); } \ + static const hb_##Type##_funcs_t *get_null () \ + { return hb_##Type##_funcs_get_empty (); } \ + } + +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (font); +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (unicode); +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (draw); +HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T (paint); + +#undef HB_DEFINE_TYPE_FUNCS_LAZY_LOADER_T #endif /* HB_MACHINERY_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.cc b/src/java.desktop/share/native/libharfbuzz/hb-map.cc index af449bea411..863a43aa704 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-map.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-map.cc @@ -56,8 +56,6 @@ hb_map_create () if (!(map = hb_object_create ())) return hb_map_get_empty (); - map->init_shallow (); - return map; } @@ -107,8 +105,6 @@ hb_map_destroy (hb_map_t *map) { if (!hb_object_destroy (map)) return; - map->fini_shallow (); - hb_free (map); } @@ -122,7 +118,7 @@ hb_map_destroy (hb_map_t *map) * * Attaches a user-data key/data pair to the specified map. * - * Return value: %true if success, %false otherwise + * Return value: `true` if success, `false` otherwise * * Since: 1.7.7 **/ @@ -149,7 +145,7 @@ hb_map_set_user_data (hb_map_t *map, * Since: 1.7.7 **/ void * -hb_map_get_user_data (hb_map_t *map, +hb_map_get_user_data (const hb_map_t *map, hb_user_data_key_t *key) { return hb_object_get_user_data (map, key); @@ -162,7 +158,7 @@ hb_map_get_user_data (hb_map_t *map, * * Tests whether memory allocation for a set was successful. * - * Return value: %true if allocation succeeded, %false otherwise + * Return value: `true` if allocation succeeded, `false` otherwise * * Since: 1.7.7 **/ @@ -178,7 +174,7 @@ hb_map_allocation_successful (const hb_map_t *map) * * Allocate a copy of @map. * - * Return value: Newly-allocated map. + * Return value: (transfer full): Newly-allocated map. * * Since: 4.4.0 **/ @@ -186,9 +182,10 @@ hb_map_t * hb_map_copy (const hb_map_t *map) { hb_map_t *copy = hb_map_create (); - if (unlikely (!copy)) return nullptr; - copy->resize (map->population); - hb_copy (*map, *copy); + if (unlikely (copy->in_error ())) + return hb_map_get_empty (); + + *copy = *map; return copy; } @@ -251,7 +248,7 @@ hb_map_del (hb_map_t *map, * * Tests whether @key is an element of @map. * - * Return value: %true if @key is found in @map, %false otherwise + * Return value: `true` if @key is found in @map, `false` otherwise * * Since: 1.7.7 **/ @@ -283,7 +280,7 @@ hb_map_clear (hb_map_t *map) * * Tests whether @map is empty (contains no elements). * - * Return value: %true if @map is empty + * Return value: `true` if @map is empty * * Since: 1.7.7 **/ @@ -317,7 +314,7 @@ hb_map_get_population (const hb_map_t *map) * Tests whether @map and @other are equal (contain the same * elements). * - * Return value: %true if the two maps are equal, %false otherwise. + * Return value: `true` if the two maps are equal, `false` otherwise. * * Since: 4.3.0 **/ @@ -339,9 +336,84 @@ hb_map_is_equal (const hb_map_t *map, * * Since: 4.4.0 **/ -HB_EXTERN unsigned int +unsigned int hb_map_hash (const hb_map_t *map) { return map->hash (); } +/** + * hb_map_update: + * @map: A map + * @other: Another map + * + * Add the contents of @other to @map. + * + * Since: 7.0.0 + **/ +HB_EXTERN void +hb_map_update (hb_map_t *map, + const hb_map_t *other) +{ + map->update (*other); +} + +/** + * hb_map_next: + * @map: A map + * @idx: (inout): Iterator internal state + * @key: (out): Key retrieved + * @value: (out): Value retrieved + * + * Fetches the next key/value paire in @map. + * + * Set @idx to -1 to get started. + * + * If the map is modified during iteration, the behavior is undefined. + * + * The order in which the key/values are returned is undefined. + * + * Return value: `true` if there was a next value, `false` otherwise + * + * Since: 7.0.0 + **/ +hb_bool_t +hb_map_next (const hb_map_t *map, + int *idx, + hb_codepoint_t *key, + hb_codepoint_t *value) +{ + return map->next (idx, key, value); +} + +/** + * hb_map_keys: + * @map: A map + * @keys: A set + * + * Add the keys of @map to @keys. + * + * Since: 7.0.0 + **/ +void +hb_map_keys (const hb_map_t *map, + hb_set_t *keys) +{ + map->keys (*keys); +} + +/** + * hb_map_values: + * @map: A map + * @values: A set + * + * Add the values of @map to @values. + * + * Since: 7.0.0 + **/ +void +hb_map_values (const hb_map_t *map, + hb_set_t *values) +{ + map->values (*values); +} diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.h b/src/java.desktop/share/native/libharfbuzz/hb-map.h index 27c19c2b589..12d8970f48f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-map.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-map.h @@ -32,6 +32,7 @@ #define HB_MAP_H #include "hb-common.h" +#include "hb-set.h" HB_BEGIN_DECLS @@ -74,7 +75,7 @@ hb_map_set_user_data (hb_map_t *map, hb_bool_t replace); HB_EXTERN void * -hb_map_get_user_data (hb_map_t *map, +hb_map_get_user_data (const hb_map_t *map, hb_user_data_key_t *key); @@ -118,6 +119,24 @@ HB_EXTERN hb_bool_t hb_map_has (const hb_map_t *map, hb_codepoint_t key); +HB_EXTERN void +hb_map_update (hb_map_t *map, + const hb_map_t *other); + +/* Pass -1 in for idx to get started. */ +HB_EXTERN hb_bool_t +hb_map_next (const hb_map_t *map, + int *idx, + hb_codepoint_t *key, + hb_codepoint_t *value); + +HB_EXTERN void +hb_map_keys (const hb_map_t *map, + hb_set_t *keys); + +HB_EXTERN void +hb_map_values (const hb_map_t *map, + hb_set_t *values); HB_END_DECLS diff --git a/src/java.desktop/share/native/libharfbuzz/hb-map.hh b/src/java.desktop/share/native/libharfbuzz/hb-map.hh index ff5a476d7a2..5c351e2c8a0 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-map.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-map.hh @@ -29,6 +29,8 @@ #include "hb.hh" +#include "hb-set.hh" + /* * hb_hashmap_t @@ -43,9 +45,9 @@ struct hb_hashmap_t hb_hashmap_t () { init (); } ~hb_hashmap_t () { fini (); } - hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (population); hb_copy (o, *this); } + hb_hashmap_t (const hb_hashmap_t& o) : hb_hashmap_t () { resize (o.population); hb_copy (o, *this); } hb_hashmap_t (hb_hashmap_t&& o) : hb_hashmap_t () { hb_swap (*this, o); } - hb_hashmap_t& operator= (const hb_hashmap_t& o) { resize (population); hb_copy (o, *this); return *this; } + hb_hashmap_t& operator= (const hb_hashmap_t& o) { reset (); resize (o.population); hb_copy (o, *this); return *this; } hb_hashmap_t& operator= (hb_hashmap_t&& o) { hb_swap (*this, o); return *this; } hb_hashmap_t (std::initializer_list> lst) : hb_hashmap_t () @@ -71,6 +73,11 @@ struct hb_hashmap_t uint32_t is_tombstone_ : 1; V value; + item_t () : key (), + hash (0), + is_used_ (false), is_tombstone_ (false), + value () {} + bool is_used () const { return is_used_; } void set_used (bool is_used) { is_used_ = is_used; } bool is_tombstone () const { return is_tombstone_; } @@ -88,17 +95,8 @@ struct hb_hashmap_t return minus_1; }; - void clear () - { - new (std::addressof (key)) K (); - new (std::addressof (value)) V (); - hash = 0; - is_used_ = false; - is_tombstone_ = false; - } - - bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); } - bool operator == (const item_t &o) { return *this == o.key; } + bool operator == (const K &o) const { return hb_deref (key) == hb_deref (o); } + bool operator == (const item_t &o) const { return *this == o.key; } hb_pair_t get_pair() const { return hb_pair_t (key, value); } hb_pair_t get_pair_ref() const { return hb_pair_t (key, value); } @@ -107,8 +105,8 @@ struct hb_hashmap_t }; hb_object_header_t header; - bool successful; /* Allocations successful */ - unsigned int population; /* Not including tombstones. */ + unsigned int successful : 1; /* Allocations successful */ + unsigned int population : 31; /* Not including tombstones. */ unsigned int occupancy; /* Including tombstones. */ unsigned int mask; unsigned int prime; @@ -118,27 +116,29 @@ struct hb_hashmap_t { if (unlikely (!a.successful || !b.successful)) return; - hb_swap (a.population, b.population); + unsigned tmp = a.population; + a.population = b.population; + b.population = tmp; + //hb_swap (a.population, b.population); hb_swap (a.occupancy, b.occupancy); hb_swap (a.mask, b.mask); hb_swap (a.prime, b.prime); hb_swap (a.items, b.items); } - void init_shallow () + void init () { + hb_object_init (this); + successful = true; population = occupancy = 0; mask = 0; prime = 0; items = nullptr; } - void init () - { - hb_object_init (this); - init_shallow (); - } - void fini_shallow () + void fini () { + hb_object_fini (this); + if (likely (items)) { unsigned size = mask + 1; for (unsigned i = 0; i < size; i++) @@ -148,11 +148,6 @@ struct hb_hashmap_t } population = occupancy = 0; } - void fini () - { - hb_object_fini (this); - fini_shallow (); - } void reset () { @@ -166,7 +161,9 @@ struct hb_hashmap_t { if (unlikely (!successful)) return false; - unsigned int power = hb_bit_storage (hb_max (population, new_population) * 2 + 8); + if (new_population != 0 && (new_population + new_population / 2) < mask) return true; + + unsigned int power = hb_bit_storage (hb_max ((unsigned) population, new_population) * 2 + 8); unsigned int new_size = 1u << power; item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t)); if (unlikely (!new_items)) @@ -175,9 +172,9 @@ struct hb_hashmap_t return false; } for (auto &_ : hb_iter (new_items, new_size)) - _.clear (); + new (&_) item_t (); - unsigned int old_size = mask + 1; + unsigned int old_size = size (); item_t *old_items = items; /* Switch to new, empty, array. */ @@ -187,67 +184,102 @@ struct hb_hashmap_t items = new_items; /* Insert back old items. */ - if (old_items) - for (unsigned int i = 0; i < old_size; i++) + for (unsigned int i = 0; i < old_size; i++) + { + if (old_items[i].is_real ()) { - if (old_items[i].is_real ()) - { - set_with_hash (old_items[i].key, - old_items[i].hash, - std::move (old_items[i].value)); - } - old_items[i].~item_t (); + set_with_hash (std::move (old_items[i].key), + old_items[i].hash, + std::move (old_items[i].value)); } + old_items[i].~item_t (); + } hb_free (old_items); return true; } + template + bool set_with_hash (KK&& key, uint32_t hash, VV&& value, bool is_delete=false) + { + if (unlikely (!successful)) return false; + if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; + item_t &item = item_for_hash (key, hash); + + if (is_delete && !(item == key)) + return true; /* Trying to delete non-existent key. */ + + if (item.is_used ()) + { + occupancy--; + if (!item.is_tombstone ()) + population--; + } + + item.key = std::forward (key); + item.value = std::forward (value); + item.hash = hash; + item.set_used (true); + item.set_tombstone (is_delete); + + occupancy++; + if (!is_delete) + population++; + + return true; + } + template - bool set (K key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward (value)); } + bool set (const K &key, VV&& value) { return set_with_hash (key, hb_hash (key), std::forward (value)); } + template + bool set (K &&key, VV&& value) { return set_with_hash (std::move (key), hb_hash (key), std::forward (value)); } - const V& get (K key) const + const V& get_with_hash (const K &key, uint32_t hash) const { if (unlikely (!items)) return item_t::default_value (); - unsigned int i = bucket_for (key); - return items[i].is_real () && items[i] == key ? items[i].value : item_t::default_value (); + auto &item = item_for_hash (key, hash); + return item.is_real () && item == key ? item.value : item_t::default_value (); + } + const V& get (const K &key) const + { + if (unlikely (!items)) return item_t::default_value (); + return get_with_hash (key, hb_hash (key)); } - void del (K key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); } + void del (const K &key) { set_with_hash (key, hb_hash (key), item_t::default_value (), true); } /* Has interface. */ - typedef const V& value_t; - value_t operator [] (K k) const { return get (k); } - bool has (K key, const V **vp = nullptr) const + const V& operator [] (K k) const { return get (k); } + template + bool has (K key, VV **vp = nullptr) const { if (unlikely (!items)) - { - if (vp) *vp = &item_t::default_value (); return false; - } - unsigned int i = bucket_for (key); - if (items[i].is_real () && items[i] == key) + auto &item = item_for_hash (key, hb_hash (key)); + if (item.is_real () && item == key) { - if (vp) *vp = &items[i].value; + if (vp) *vp = std::addressof (item.value); return true; } else - { - if (vp) *vp = &item_t::default_value (); return false; - } } /* Projection. */ V operator () (K k) const { return get (k); } + unsigned size () const { return mask ? mask + 1 : 0; } + void clear () { if (unlikely (!successful)) return; - if (items) - for (auto &_ : hb_iter (items, mask + 1)) - _.clear (); + for (auto &_ : hb_iter (items, size ())) + { + /* Reconstruct items. */ + _.~item_t (); + new (&_) item_t (); + } population = occupancy = 0; } @@ -257,11 +289,10 @@ struct hb_hashmap_t uint32_t hash () const { - uint32_t h = 0; - for (const auto &item : + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real)) - h ^= item.total_hash (); - return h; + return + + iter_items () + | hb_reduce ([] (uint32_t h, const item_t &_) { return h ^ _.total_hash (); }, (uint32_t) 0u) + ; } bool is_equal (const hb_hashmap_t &other) const @@ -269,7 +300,7 @@ struct hb_hashmap_t if (population != other.population) return false; for (auto pair : iter ()) - if (get (pair.first) != pair.second) + if (other.get (pair.first) != pair.second) return false; return true; @@ -279,78 +310,98 @@ struct hb_hashmap_t unsigned int get_population () const { return population; } + void update (const hb_hashmap_t &other) + { + if (unlikely (!successful)) return; + + hb_copy (other, *this); + } + + void keys (hb_set_t &keys_) const + { + hb_copy (keys() , keys_); + } + + void values (hb_set_t &values_) const + { + hb_copy (values() , values_); + } + /* * Iterator */ - auto iter () const HB_AUTO_RETURN + + auto iter_items () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) + + hb_iter (items, size ()) | hb_filter (&item_t::is_real) - | hb_map (&item_t::get_pair) ) auto iter_ref () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) + + iter_items () | hb_map (&item_t::get_pair_ref) ) - auto keys () const HB_AUTO_RETURN + auto iter () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) + + iter_items () + | hb_map (&item_t::get_pair) + ) + auto keys_ref () const HB_AUTO_RETURN + ( + + iter_items () | hb_map (&item_t::key) + ) + auto keys () const HB_AUTO_RETURN + ( + + keys_ref () | hb_map (hb_ridentity) ) - auto values () const HB_AUTO_RETURN + auto values_ref () const HB_AUTO_RETURN ( - + hb_array (items, mask ? mask + 1 : 0) - | hb_filter (&item_t::is_real) + + iter_items () | hb_map (&item_t::value) + ) + auto values () const HB_AUTO_RETURN + ( + + values_ref () | hb_map (hb_ridentity) ) - /* Sink interface. */ - hb_hashmap_t& operator << (const hb_pair_t& v) - { set (v.first, v.second); return *this; } - - protected: - - template - bool set_with_hash (K key, uint32_t hash, VV&& value, bool is_delete=false) + /* C iterator. */ + bool next (int *idx, + K *key, + V *value) const { - if (unlikely (!successful)) return false; - if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; - unsigned int i = bucket_for_hash (key, hash); + unsigned i = (unsigned) (*idx + 1); - if (is_delete && items[i].key != key) - return true; /* Trying to delete non-existent key. */ + unsigned count = size (); + while (i < count && !items[i].is_real ()) + i++; - if (items[i].is_used ()) + if (i >= count) { - occupancy--; - if (!items[i].is_tombstone ()) - population--; + *idx = -1; + return false; } - items[i].key = key; - items[i].value = std::forward (value); - items[i].hash = hash; - items[i].set_used (true); - items[i].set_tombstone (is_delete); - - occupancy++; - if (!is_delete) - population++; + *key = items[i].key; + *value = items[i].value; + *idx = (signed) i; return true; } - unsigned int bucket_for (const K &key) const - { - return bucket_for_hash (key, hb_hash (key)); - } - - unsigned int bucket_for_hash (const K &key, uint32_t hash) const + /* Sink interface. */ + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (v.first, v.second); return *this; } + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (v.first, std::move (v.second)); return *this; } + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (std::move (v.first), v.second); return *this; } + hb_hashmap_t& operator << (const hb_pair_t& v) + { set (std::move (v.first), std::move (v.second)); return *this; } + + item_t& item_for_hash (const K &key, uint32_t hash) const { hash &= 0x3FFFFFFF; // We only store lower 30bit of hash unsigned int i = hash % prime; @@ -359,12 +410,12 @@ struct hb_hashmap_t while (items[i].is_used ()) { if (items[i].hash == hash && items[i] == key) - return i; + return items[i]; if (tombstone == (unsigned) -1 && items[i].is_tombstone ()) tombstone = i; i = (i + ++step) & mask; } - return tombstone == (unsigned) -1 ? i : tombstone; + return items[tombstone == (unsigned) -1 ? i : tombstone]; } static unsigned int prime_for (unsigned int shift) @@ -443,4 +494,5 @@ struct hb_map_t : hb_hashmap_t auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_ident template using hb_add_pointer = decltype (_hb_try_add_pointer (hb_prioritize)); -/* TODO Add feature-parity to std::decay. */ -template using hb_decay = hb_remove_const>; +template using hb_decay = typename std::decay::type; #define hb_is_convertible(From,To) std::is_convertible::value @@ -133,6 +132,18 @@ struct template constexpr auto operator () (T *v) const HB_AUTO_RETURN (*v) + + template constexpr auto + operator () (const hb::shared_ptr& v) const HB_AUTO_RETURN (*v) + + template constexpr auto + operator () (hb::shared_ptr& v) const HB_AUTO_RETURN (*v) + + template constexpr auto + operator () (const hb::unique_ptr& v) const HB_AUTO_RETURN (*v) + + template constexpr auto + operator () (hb::unique_ptr& v) const HB_AUTO_RETURN (*v) } HB_FUNCOBJ (hb_deref); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-multimap.hh b/src/java.desktop/share/native/libharfbuzz/hb-multimap.hh new file mode 100644 index 00000000000..b4a8cc62a3e --- /dev/null +++ b/src/java.desktop/share/native/libharfbuzz/hb-multimap.hh @@ -0,0 +1,92 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#ifndef HB_MULTIMAP_HH +#define HB_MULTIMAP_HH + +#include "hb.hh" +#include "hb-map.hh" +#include "hb-vector.hh" + + +/* + * hb_multimap_t + */ + +struct hb_multimap_t +{ + void add (hb_codepoint_t k, hb_codepoint_t v) + { + hb_codepoint_t *i; + if (multiples_indices.has (k, &i)) + { + multiples_values[*i].push (v); + return; + } + + hb_codepoint_t *old_v; + if (singulars.has (k, &old_v)) + { + hb_codepoint_t old = *old_v; + singulars.del (k); + + multiples_indices.set (k, multiples_values.length); + auto *vec = multiples_values.push (); + + vec->push (old); + vec->push (v); + + return; + } + + singulars.set (k, v); + } + + hb_array_t get (hb_codepoint_t k) const + { + const hb_codepoint_t *v; + if (singulars.has (k, &v)) + return hb_array (v, 1); + + hb_codepoint_t *i; + if (multiples_indices.has (k, &i)) + return multiples_values[*i].as_array (); + + return hb_array_t (); + } + + bool in_error () const + { + return singulars.in_error () || multiples_indices.in_error () || multiples_values.in_error (); + } + + protected: + hb_map_t singulars; + hb_map_t multiples_indices; + hb_vector_t> multiples_values; +}; + + + +#endif /* HB_MULTIMAP_HH */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh b/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh index 8b62afaf94e..72012bd2e64 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-mutex.hh @@ -60,7 +60,7 @@ typedef pthread_mutex_t hb_mutex_impl_t; #elif !defined(HB_NO_MT) && !defined(HB_MUTEX_IMPL_STD_MUTEX) && defined(_WIN32) typedef CRITICAL_SECTION hb_mutex_impl_t; -#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) +#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) #define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0) #else #define hb_mutex_impl_init(M) InitializeCriticalSection (M) @@ -97,6 +97,9 @@ struct hb_mutex_t /* Create space for, but do not initialize m. */ alignas(hb_mutex_impl_t) char m[sizeof (hb_mutex_impl_t)]; + hb_mutex_t () { init (); } + ~hb_mutex_t () { fini (); } + #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wcast-align" void init () { hb_mutex_impl_init ((hb_mutex_impl_t *) m); } @@ -108,10 +111,11 @@ struct hb_mutex_t struct hb_lock_t { - hb_lock_t (hb_mutex_t &mutex_) : mutex (mutex_) { mutex.lock (); } - ~hb_lock_t () { mutex.unlock (); } + hb_lock_t (hb_mutex_t &mutex_) : mutex (&mutex_) { mutex->lock (); } + hb_lock_t (hb_mutex_t *mutex_) : mutex (mutex_) { if (mutex) mutex->lock (); } + ~hb_lock_t () { if (mutex) mutex->unlock (); } private: - hb_mutex_t &mutex; + hb_mutex_t *mutex; }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-null.hh b/src/java.desktop/share/native/libharfbuzz/hb-null.hh index 4403867f5c3..8a9ebbfc2d7 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-null.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-null.hh @@ -39,6 +39,24 @@ #define HB_NULL_POOL_SIZE 448 +template +struct _hb_has_min_size : hb_false_type {}; +template +struct _hb_has_min_size> + : hb_true_type {}; +template +using hb_has_min_size = _hb_has_min_size; +#define hb_has_min_size(T) hb_has_min_size::value + +template +struct _hb_has_null_size : hb_false_type {}; +template +struct _hb_has_null_size> + : hb_true_type {}; +template +using hb_has_null_size = _hb_has_null_size; +#define hb_has_null_size(T) hb_has_null_size::value + /* Use SFINAE to sniff whether T has min_size; in which case return the larger * of sizeof(T) and T::null_size, otherwise return sizeof(T). * @@ -117,8 +135,19 @@ struct NullHelper }; \ namespace Namespace { \ static_assert (true, "") /* Require semicolon after. */ +#define DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1(Namespace, Type, Size) \ + } /* Close namespace. */ \ + extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Size]; \ + template \ + struct Null> { \ + static Namespace::Type const & get_null () { \ + return *reinterpret_cast *> (_hb_Null_##Namespace##_##Type); \ + } \ + }; \ + namespace Namespace { \ + static_assert (true, "") /* Require semicolon after. */ #define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \ - const unsigned char _hb_Null_##Namespace##_##Type[hb_null_size (Namespace::Type)] + const unsigned char _hb_Null_##Namespace##_##Type[sizeof (_hb_Null_##Namespace##_##Type)] /* Specializations for arbitrary-content Null objects expressed as struct initializer. */ #define DECLARE_NULL_INSTANCE(Type) \ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh index 9d2867e4835..07f3ebe0c7d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh @@ -31,7 +31,7 @@ #include "hb.hh" -#line 35 "hb-number-parser.hh" +#line 32 "hb-number-parser.hh" static const unsigned char _double_parser_trans_keys[] = { 0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u, 46u, 101u, 0 @@ -135,12 +135,12 @@ strtod_rl (const char *p, const char **end_ptr /* IN/OUT */) int cs; -#line 139 "hb-number-parser.hh" +#line 132 "hb-number-parser.hh" { cs = double_parser_start; } -#line 144 "hb-number-parser.hh" +#line 135 "hb-number-parser.hh" { int _slen; int _trans; @@ -198,7 +198,7 @@ _resume: exp_overflow = true; } break; -#line 202 "hb-number-parser.hh" +#line 187 "hb-number-parser.hh" } _again: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-number.cc b/src/java.desktop/share/native/libharfbuzz/hb-number.cc index f4ce693d8ed..37bc8b87399 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-number.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-number.cc @@ -24,7 +24,6 @@ */ #include "hb.hh" -#include "hb-machinery.hh" #include "hb-number.hh" #include "hb-number-parser.hh" diff --git a/src/java.desktop/share/native/libharfbuzz/hb-object.hh b/src/java.desktop/share/native/libharfbuzz/hb-object.hh index 436c37aa1b7..ef675f835f1 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-object.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-object.hh @@ -69,7 +69,7 @@ struct hb_lockable_set_t item = items.push (v); l.unlock (); } - return item; + return items.in_error () ? nullptr : item; } template @@ -80,7 +80,7 @@ struct hb_lockable_set_t if (item) { item_t old = *item; - *item = items[items.length - 1]; + *item = std::move (items.tail ()); items.pop (); l.unlock (); old.fini (); @@ -123,7 +123,7 @@ struct hb_lockable_set_t l.lock (); while (items.length) { - item_t old = items[items.length - 1]; + item_t old = items.tail (); items.pop (); l.unlock (); old.fini (); @@ -144,14 +144,14 @@ struct hb_reference_count_t { mutable hb_atomic_int_t ref_count; - void init (int v = 1) { ref_count.set_relaxed (v); } - int get_relaxed () const { return ref_count.get_relaxed (); } + void init (int v = 1) { ref_count = v; } + int get_relaxed () const { return ref_count; } int inc () const { return ref_count.inc (); } int dec () const { return ref_count.dec (); } - void fini () { ref_count.set_relaxed (-0x0000DEAD); } + void fini () { ref_count = -0x0000DEAD; } - bool is_inert () const { return !ref_count.get_relaxed (); } - bool is_valid () const { return ref_count.get_relaxed () > 0; } + bool is_inert () const { return !ref_count; } + bool is_valid () const { return ref_count > 0; } }; @@ -175,14 +175,34 @@ struct hb_user_data_array_t void init () { lock.init (); items.init (); } - HB_INTERNAL bool set (hb_user_data_key_t *key, - void * data, - hb_destroy_func_t destroy, - hb_bool_t replace); + void fini () { items.fini (lock); lock.fini (); } + + bool set (hb_user_data_key_t *key, + void * data, + hb_destroy_func_t destroy, + hb_bool_t replace) + { + if (!key) + return false; - HB_INTERNAL void *get (hb_user_data_key_t *key); + if (replace) { + if (!data && !destroy) { + items.remove (key, lock); + return true; + } + } + hb_user_data_item_t item = {key, data, destroy}; + bool ret = !!items.replace_or_insert (item, lock, (bool) replace); - void fini () { items.fini (lock); lock.fini (); } + return ret; + } + + void *get (hb_user_data_key_t *key) + { + hb_user_data_item_t item = {nullptr, nullptr, nullptr}; + + return items.find (key, &item, lock) ? item.data : nullptr; + } }; @@ -214,23 +234,26 @@ static inline void hb_object_trace (const Type *obj, const char *function) obj ? obj->header.ref_count.get_relaxed () : 0); } -template -static inline Type *hb_object_create () +template +static inline Type *hb_object_create (Ts... ds) { Type *obj = (Type *) hb_calloc (1, sizeof (Type)); if (unlikely (!obj)) return obj; + new (obj) Type (std::forward (ds)...); + hb_object_init (obj); hb_object_trace (obj, HB_FUNC); + return obj; } template static inline void hb_object_init (Type *obj) { obj->header.ref_count.init (); - obj->header.writable.set_relaxed (true); + obj->header.writable = true; obj->header.user_data.init (); } template @@ -241,12 +264,12 @@ static inline bool hb_object_is_valid (const Type *obj) template static inline bool hb_object_is_immutable (const Type *obj) { - return !obj->header.writable.get_relaxed (); + return !obj->header.writable; } template static inline void hb_object_make_immutable (const Type *obj) { - obj->header.writable.set_relaxed (false); + obj->header.writable = false; } template static inline Type *hb_object_reference (Type *obj) @@ -269,18 +292,22 @@ static inline bool hb_object_destroy (Type *obj) return false; hb_object_fini (obj); + + if (!std::is_trivially_destructible::value) + obj->~Type (); + return true; } template static inline void hb_object_fini (Type *obj) { obj->header.ref_count.fini (); /* Do this before user_data */ - hb_user_data_array_t *user_data = obj->header.user_data.get (); + hb_user_data_array_t *user_data = obj->header.user_data.get_acquire (); if (user_data) { user_data->fini (); hb_free (user_data); - user_data = nullptr; + obj->header.user_data.set_relaxed (nullptr); } } template @@ -295,7 +322,7 @@ static inline bool hb_object_set_user_data (Type *obj, assert (hb_object_is_valid (obj)); retry: - hb_user_data_array_t *user_data = obj->header.user_data.get (); + hb_user_data_array_t *user_data = obj->header.user_data.get_acquire (); if (unlikely (!user_data)) { user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1); @@ -320,7 +347,7 @@ static inline void *hb_object_get_user_data (Type *obj, if (unlikely (!obj || obj->header.is_inert ())) return nullptr; assert (hb_object_is_valid (obj)); - hb_user_data_array_t *user_data = obj->header.user_data.get (); + hb_user_data_array_t *user_data = obj->header.user_data.get_acquire (); if (!user_data) return nullptr; return user_data->get (key); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh index 1dff7c414cc..c02eb41d100 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-open-file.hh @@ -90,7 +90,7 @@ typedef struct OpenTypeOffsetTable { if (table_count) { - + tables.sub_array (start_offset, table_count) + + tables.as_array ().sub_array (start_offset, table_count) | hb_map (&TableRecord::tag) | hb_sink (hb_array (table_tags, *table_count)) ; @@ -158,7 +158,7 @@ typedef struct OpenTypeOffsetTable return_trace (false); if (likely (len)) - memcpy (start, blob->data, len); + hb_memcpy (start, blob->data, len); /* 4-byte alignment. */ c->align (4); diff --git a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh index a4dfb3615e3..4639d80babc 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-open-type.hh @@ -105,7 +105,7 @@ struct IntType bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: BEInt v; @@ -141,27 +141,29 @@ typedef HBINT32 FWORD32; /* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */ typedef HBUINT16 UFWORD; -/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ -struct F2DOT14 : HBINT16 +template +struct HBFixed : Type { - F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; } - // 16384 means 1<<14 - float to_float () const { return ((int32_t) v) / 16384.f; } - void set_float (float f) { v = roundf (f * 16384.f); } + static constexpr float shift = (float) (1 << fraction_bits); + static_assert (Type::static_size * 8 > fraction_bits, ""); + + operator signed () const = delete; + operator unsigned () const = delete; + typename Type::type to_int () const { return Type::v; } + void set_int (typename Type::type i ) { Type::v = i; } + float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; } + void set_float (float f) { Type::v = roundf (f * shift); } public: - DEFINE_SIZE_STATIC (2); + DEFINE_SIZE_STATIC (Type::static_size); }; +/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */ +using F2DOT14 = HBFixed; +using F4DOT12 = HBFixed; +using F6DOT10 = HBFixed; + /* 32-bit signed fixed-point number (16.16). */ -struct HBFixed : HBINT32 -{ - HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; } - // 65536 means 1<<16 - float to_float () const { return ((int32_t) v) / 65536.f; } - void set_float (float f) { v = roundf (f * 65536.f); } - public: - DEFINE_SIZE_STATIC (4); -}; +using F16DOT16 = HBFixed; /* Date represented in number of seconds since 12:00 midnight, January 1, * 1904. The value is represented as a signed 64-bit integer. */ @@ -170,7 +172,7 @@ struct LONGDATETIME bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: HBINT32 major; @@ -196,6 +198,10 @@ struct HBGlyphID16 : HBUINT16 { HBGlyphID16& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; } }; +struct HBGlyphID24 : HBUINT24 +{ + HBGlyphID24& operator = (uint32_t i) { HBUINT24::operator= (i); return *this; } +}; /* Script/language-system/feature index */ struct Index : HBUINT16 { @@ -208,6 +214,12 @@ typedef Index NameID; struct VarIdx : HBUINT32 { static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu; + static_assert (NO_VARIATION == HB_OT_LAYOUT_NO_VARIATIONS_INDEX, ""); + static uint32_t add (uint32_t i, unsigned short v) + { + if (i == NO_VARIATION) return i; + return i + v; + } VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; } }; DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx); @@ -300,6 +312,10 @@ struct _hb_has_null template struct OffsetTo : Offset { + // Make sure Type is not unbounded; works only for types that are fully defined at OffsetTo time. + static_assert (has_null == false || + (hb_has_null_size (Type) || !hb_has_min_size (Type)), ""); + HB_DELETE_COPY_ASSIGN (OffsetTo); OffsetTo () = default; @@ -450,14 +466,16 @@ struct UnsizedArrayOf { unsigned int i = (unsigned int) i_; const Type *p = &arrayZ[i]; - if (unlikely (p < arrayZ)) return Null (Type); /* Overflowed. */ + if (unlikely ((const void *) p < (const void *) arrayZ)) return Null (Type); /* Overflowed. */ + _hb_compiler_memory_r_barrier (); return *p; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; Type *p = &arrayZ[i]; - if (unlikely (p < arrayZ)) return Crap (Type); /* Overflowed. */ + if (unlikely ((const void *) p < (const void *) arrayZ)) return Crap (Type); /* Overflowed. */ + _hb_compiler_memory_r_barrier (); return *p; } @@ -486,10 +504,10 @@ struct UnsizedArrayOf void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1) { as_array (len).qsort (start, end); } - bool serialize (hb_serialize_context_t *c, unsigned int items_len) + bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) { TRACE_SERIALIZE (this); - if (unlikely (!c->extend (this, items_len))) return_trace (false); + if (unlikely (!c->extend_size (this, get_size (items_len), clear))) return_trace (false); return_trace (true); } template *p = &this->arrayZ[i]; - if (unlikely (p < this->arrayZ)) return Null (Type); /* Overflowed. */ + if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Null (Type); /* Overflowed. */ + _hb_compiler_memory_r_barrier (); return this+*p; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; const OffsetTo *p = &this->arrayZ[i]; - if (unlikely (p < this->arrayZ)) return Crap (Type); /* Overflowed. */ + if (unlikely ((const void *) p < (const void *) this->arrayZ)) return Crap (Type); /* Overflowed. */ + _hb_compiler_memory_r_barrier (); return this+*p; } @@ -608,12 +628,14 @@ struct ArrayOf { unsigned int i = (unsigned int) i_; if (unlikely (i >= len)) return Null (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i]; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= len)) return Crap (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i]; } @@ -635,14 +657,9 @@ struct ArrayOf operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - hb_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count); } - hb_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count); } + /* Faster range-based for loop. */ + const Type *begin () const { return arrayZ; } + const Type *end () const { return arrayZ + len; } template Type &lsearch (const T &x, Type ¬_found = Crap (Type)) @@ -656,15 +673,15 @@ struct ArrayOf unsigned int to_store = (unsigned int) -1) const { return as_array ().lfind (x, i, not_found, to_store); } - void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) - { as_array ().qsort (start, end); } + void qsort () + { as_array ().qsort (); } - HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len) + HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len, bool clear = true) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); - if (unlikely (!c->extend (this))) return_trace (false); + if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); return_trace (true); } template using Array16Of = ArrayOf; +template using Array24Of = ArrayOf; template using Array32Of = ArrayOf; using PString = ArrayOf; @@ -738,26 +756,28 @@ template using Array16OfOffset32To = ArrayOf using Array32OfOffset32To = ArrayOf, HBUINT32>; /* Array of offsets relative to the beginning of the array itself. */ -template -struct List16OfOffset16To : Array16OfOffset16To +template +struct List16OfOffsetTo : ArrayOf, HBUINT16> { const Type& operator [] (int i_) const { unsigned int i = (unsigned int) i_; if (unlikely (i >= this->len)) return Null (Type); + _hb_compiler_memory_r_barrier (); return this+this->arrayZ[i]; } const Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= this->len)) return Crap (Type); + _hb_compiler_memory_r_barrier (); return this+this->arrayZ[i]; } bool subset (hb_subset_context_t *c) const { TRACE_SUBSET (this); - struct List16OfOffset16To *out = c->serializer->embed (*this); + struct List16OfOffsetTo *out = c->serializer->embed (*this); if (unlikely (!out)) return_trace (false); unsigned int count = this->len; for (unsigned int i = 0; i < count; i++) @@ -769,10 +789,13 @@ struct List16OfOffset16To : Array16OfOffset16To bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const { TRACE_SANITIZE (this); - return_trace (Array16OfOffset16To::sanitize (c, this, std::forward (ds)...)); + return_trace ((Array16Of>::sanitize (c, this, std::forward (ds)...))); } }; +template +using List16OfOffset16To = List16OfOffsetTo; + /* An array starting at second element. */ template struct HeadlessArrayOf @@ -785,12 +808,14 @@ struct HeadlessArrayOf { unsigned int i = (unsigned int) i_; if (unlikely (i >= lenP1 || !i)) return Null (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i-1]; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= lenP1 || !i)) return Crap (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i-1]; } unsigned int get_size () const @@ -809,21 +834,25 @@ struct HeadlessArrayOf operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - bool serialize (hb_serialize_context_t *c, unsigned int items_len) + /* Faster range-based for loop. */ + const Type *begin () const { return arrayZ; } + const Type *end () const { return arrayZ + get_length (); } + + HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned int items_len, bool clear = true) { TRACE_SERIALIZE (this); if (unlikely (!c->extend_min (this))) return_trace (false); c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW); - if (unlikely (!c->extend (this))) return_trace (false); + if (unlikely (!c->extend_size (this, get_size (), clear))) return_trace (false); return_trace (true); } template - bool serialize (hb_serialize_context_t *c, Iterator items) + HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items) { TRACE_SERIALIZE (this); - unsigned count = items.len (); - if (unlikely (!serialize (c, count))) return_trace (false); + unsigned count = hb_len (items); + if (unlikely (!serialize (c, count, false))) return_trace (false); /* TODO Umm. Just exhaust the iterator instead? Being extra * cautious right now.. */ for (unsigned i = 0; i < count; i++, ++items) @@ -869,12 +898,14 @@ struct ArrayOfM1 { unsigned int i = (unsigned int) i_; if (unlikely (i > lenM1)) return Null (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i]; } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i > lenM1)) return Crap (Type); + _hb_compiler_memory_r_barrier (); return arrayZ[i]; } unsigned int get_size () const @@ -923,14 +954,9 @@ struct SortedArrayOf : ArrayOf operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int count) const - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int count) - { return as_array ().sub_array (start_offset, count); } - hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) - { return as_array ().sub_array (start_offset, count); } + /* Faster range-based for loop. */ + const Type *begin () const { return this->arrayZ; } + const Type *end () const { return this->arrayZ + this->len; } bool serialize (hb_serialize_context_t *c, unsigned int items_len) { @@ -961,6 +987,7 @@ struct SortedArrayOf : ArrayOf }; template using SortedArray16Of = SortedArrayOf; +template using SortedArray24Of = SortedArrayOf; template using SortedArray32Of = SortedArrayOf; /* @@ -1053,12 +1080,14 @@ struct VarSizedBinSearchArrayOf { unsigned int i = (unsigned int) i_; if (unlikely (i >= get_length ())) return Null (Type); + _hb_compiler_memory_r_barrier (); return StructAtOffset (&bytesZ, i * header.unitSize); } Type& operator [] (int i_) { unsigned int i = (unsigned int) i_; if (unlikely (i >= get_length ())) return Crap (Type); + _hb_compiler_memory_r_barrier (); return StructAtOffset (&bytesZ, i * header.unitSize); } unsigned int get_length () const diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh index 54c7ecdf294..d31a328e8ad 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff-common.hh @@ -66,95 +66,25 @@ struct CFFIndex { TRACE_SERIALIZE (this); unsigned int size = get_size (); - CFFIndex *out = c->allocate_size (size); + CFFIndex *out = c->allocate_size (size, false); if (likely (out)) - memcpy (out, this, size); + hb_memcpy (out, this, size); return_trace (out); } + template bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const byte_str_array_t &byteArray) + const Iterable &iterable) { TRACE_SERIALIZE (this); - - if (byteArray.length == 0) - { - COUNT *dest = c->allocate_min (); - if (unlikely (!dest)) return_trace (false); - *dest = 0; - return_trace (true); - } - - /* serialize CFFIndex header */ - if (unlikely (!c->extend_min (this))) return_trace (false); - this->count = byteArray.length; - this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (byteArray.length + 1)))) - return_trace (false); - - /* serialize indices */ - unsigned int offset = 1; - unsigned int i = 0; - for (; i < byteArray.length; i++) - { - set_offset_at (i, offset); - offset += byteArray[i].get_size (); - } - set_offset_at (i, offset); - - /* serialize data */ - for (unsigned int i = 0; i < byteArray.length; i++) - { - const hb_ubytes_t &bs = byteArray[i]; - unsigned char *dest = c->allocate_size (bs.length); - if (unlikely (!dest)) return_trace (false); - memcpy (dest, &bs[0], bs.length); - } - - return_trace (true); - } - - bool serialize (hb_serialize_context_t *c, - unsigned int offSize_, - const str_buff_vec_t &buffArray) - { - byte_str_array_t byteArray; - byteArray.init (); - byteArray.resize (buffArray.length); - for (unsigned int i = 0; i < byteArray.length; i++) - byteArray[i] = hb_ubytes_t (buffArray[i].arrayZ, buffArray[i].length); - bool result = this->serialize (c, offSize_, byteArray); - byteArray.fini (); - return result; - } - - template - bool serialize (hb_serialize_context_t *c, - Iterator it) - { - TRACE_SERIALIZE (this); - serialize_header(c, + it | hb_map ([] (const hb_ubytes_t &_) { return _.length; })); + auto it = hb_iter (iterable); + serialize_header(c, + it | hb_map (hb_iter) | hb_map (hb_len)); for (const auto &_ : +it) - _.copy (c); + hb_iter (_).copy (c); return_trace (true); } - bool serialize (hb_serialize_context_t *c, - const byte_str_array_t &byteArray) - { return serialize (c, + hb_iter (byteArray)); } - - bool serialize (hb_serialize_context_t *c, - const str_buff_vec_t &buffArray) - { - auto it = - + hb_iter (buffArray) - | hb_map ([] (const str_buff_t &_) { return hb_ubytes_t (_.arrayZ, _.length); }) - ; - return serialize (c, it); - } - template bool serialize_header (hb_serialize_context_t *c, @@ -171,7 +101,7 @@ struct CFFIndex if (!this->count) return_trace (true); if (unlikely (!c->extend (this->offSize))) return_trace (false); this->offSize = off_size; - if (unlikely (!c->allocate_size (off_size * (this->count + 1)))) + if (unlikely (!c->allocate_size (off_size * (this->count + 1), false))) return_trace (false); /* serialize indices */ @@ -179,14 +109,27 @@ struct CFFIndex unsigned int i = 0; for (unsigned _ : +it) { - CFFIndex::set_offset_at (i++, offset); + set_offset_at (i++, offset); offset += _; } - CFFIndex::set_offset_at (i, offset); + set_offset_at (i, offset); return_trace (true); } + template + static unsigned total_size (const Iterable &iterable) + { + auto it = + hb_iter (iterable) | hb_map (hb_iter) | hb_map (hb_len); + if (!it) return 0; + + unsigned total = + it | hb_reduce (hb_add, 0); + unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8; + + return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total; + } + void set_offset_at (unsigned int index, unsigned int offset) { assert (index <= count); @@ -207,10 +150,14 @@ struct CFFIndex unsigned int size = offSize; const HBUINT8 *p = offsets + size * index; - unsigned int offset = 0; - for (; size; size--) - offset = (offset << 8) + *p++; - return offset; + switch (size) + { + case 1: return * (HBUINT8 *) p; + case 2: return * (HBUINT16 *) p; + case 3: return * (HBUINT24 *) p; + case 4: return * (HBUINT32 *) p; + default: return 0; + } } unsigned int length_at (unsigned int index) const @@ -229,6 +176,7 @@ struct CFFIndex hb_ubytes_t operator [] (unsigned int index) const { if (unlikely (index >= count)) return hb_ubytes_t (); + _hb_compiler_memory_r_barrier (); unsigned length = length_at (index); if (unlikely (!length)) return hb_ubytes_t (); return hb_ubytes_t (data_base () + offset_at (index) - 1, length); @@ -280,7 +228,7 @@ struct CFFIndexOf : CFFIndex if (unlikely (!c->extend_min (this))) return_trace (false); this->count = dataArrayLen; this->offSize = offSize_; - if (unlikely (!c->allocate_size (offSize_ * (dataArrayLen + 1)))) + if (unlikely (!c->allocate_size (offSize_ * (dataArrayLen + 1), false))) return_trace (false); /* serialize indices */ @@ -288,10 +236,10 @@ struct CFFIndexOf : CFFIndex unsigned int i = 0; for (; i < dataArrayLen; i++) { - CFFIndex::set_offset_at (i, offset); + this->set_offset_at (i, offset); offset += dataSizeArray[i]; } - CFFIndex::set_offset_at (i, offset); + this->set_offset_at (i, offset); /* serialize data */ for (unsigned int i = 0; i < dataArrayLen; i++) @@ -324,13 +272,12 @@ struct Dict : UnsizedByteStr template static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, V value, op_code_t intOp) { - // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation - if (/*unlikely*/ (!serialize_int (c, intOp, value))) + if (unlikely ((!serialize_int (c, intOp, value)))) return false; TRACE_SERIALIZE (this); /* serialize the opcode */ - HBUINT8 *p = c->allocate_size (OpCode_Size (op)); + HBUINT8 *p = c->allocate_size (OpCode_Size (op), false); if (unlikely (!p)) return_trace (false); if (Is_OpCode_ESC (op)) { @@ -415,9 +362,8 @@ struct FDSelect0 { TRACE_SANITIZE (this); if (unlikely (!(c->check_struct (this)))) return_trace (false); - for (unsigned int i = 0; i < c->get_num_glyphs (); i++) - if (unlikely (!fds[i].sanitize (c))) - return_trace (false); + if (unlikely (!c->check_array (fds, c->get_num_glyphs ()))) + return_trace (false); return_trace (true); } @@ -471,14 +417,20 @@ struct FDSelect3_4 return_trace (true); } - hb_codepoint_t get_fd (hb_codepoint_t glyph) const + static int _cmp_range (const void *_key, const void *_item) { - unsigned int i; - for (i = 1; i < nRanges (); i++) - if (glyph < ranges[i].first) - break; + hb_codepoint_t glyph = * (hb_codepoint_t *) _key; + FDSelect3_4_Range *range = (FDSelect3_4_Range *) _item; - return (hb_codepoint_t) ranges[i - 1].fd; + if (glyph < range[0].first) return -1; + if (glyph < range[1].first) return 0; + return +1; + } + + hb_codepoint_t get_fd (hb_codepoint_t glyph) const + { + auto *range = hb_bsearch (glyph, &ranges[0], nRanges () - 1, sizeof (ranges[0]), _cmp_range); + return range ? range->fd : ranges[nRanges () - 1].fd; } GID_TYPE &nRanges () { return ranges.len; } @@ -501,9 +453,9 @@ struct FDSelect { TRACE_SERIALIZE (this); unsigned int size = src.get_size (num_glyphs); - FDSelect *dest = c->allocate_size (size); + FDSelect *dest = c->allocate_size (size, false); if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); + hb_memcpy (dest, &src, size); return_trace (true); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc index 9173b9d8600..505af15e5c5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.cc @@ -422,8 +422,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph } else { - extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ()); - extents->width = font->em_scalef_x (bounds.max.x.to_real ()) - extents->x_bearing; + extents->x_bearing = roundf (bounds.min.x.to_real ()); + extents->width = roundf (bounds.max.x.to_real () - extents->x_bearing); } if (bounds.min.y >= bounds.max.y) { @@ -432,10 +432,12 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph } else { - extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ()); - extents->height = font->em_scalef_y (bounds.min.y.to_real ()) - extents->y_bearing; + extents->y_bearing = roundf (bounds.max.y.to_real ()); + extents->height = roundf (bounds.min.y.to_real () - extents->y_bearing); } + font->scale_glyph_extents (extents); + return true; } @@ -551,6 +553,15 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin return true; } +bool OT::cff1::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const +{ + funcs->push_clip_glyph (data, glyph, font); + funcs->color (data, true, foreground); + funcs->pop_clip (data); + + return true; +} + bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const { #ifdef HB_NO_OT_FONT_CFF diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh index b773956662f..60bc308f90c 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-table.hh @@ -30,6 +30,7 @@ #include "hb-ot-cff-common.hh" #include "hb-subset-cff1.hh" #include "hb-draw.hh" +#include "hb-paint.hh" #define HB_STRING_ARRAY_NAME cff1_std_strings #define HB_STRING_ARRAY_LIST "hb-ot-cff1-std-str.hh" @@ -175,7 +176,7 @@ struct Encoding unsigned int size = src.get_size (); Encoding *dest = c->allocate_size (size); if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); + hb_memcpy (dest, &src, size); return_trace (true); } @@ -471,7 +472,7 @@ struct Charset unsigned int size = src.get_size (num_glyphs); Charset *dest = c->allocate_size (size); if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); + hb_memcpy (dest, &src, size); return_trace (true); } @@ -617,7 +618,6 @@ struct CFF1StringIndex : CFF1Index } byte_str_array_t bytesArray; - bytesArray.init (); if (!bytesArray.resize (sidmap.get_population ())) return_trace (false); for (unsigned int i = 0; i < strings.count; i++) @@ -628,7 +628,6 @@ struct CFF1StringIndex : CFF1Index } bool result = CFF1Index::serialize (c, bytesArray); - bytesArray.fini (); return_trace (result); } }; @@ -813,7 +812,7 @@ struct cff1_top_dict_opset_t : top_dict_opset_t break; default: - env.last_offset = env.str_ref.offset; + env.last_offset = env.str_ref.get_offset (); top_dict_opset_t::process_op (op, env, dictval); /* Record this operand below if stack is empty, otherwise done */ if (!env.argStack.is_empty ()) return; @@ -903,8 +902,6 @@ struct cff1_private_dict_opset_t : dict_opset_t case OpCode_FamilyOtherBlues: case OpCode_StemSnapH: case OpCode_StemSnapV: - env.clear_args (); - break; case OpCode_StdHW: case OpCode_StdVW: case OpCode_BlueScale: @@ -916,7 +913,6 @@ struct cff1_private_dict_opset_t : dict_opset_t case OpCode_initialRandomSeed: case OpCode_defaultWidthX: case OpCode_nominalWidthX: - val.single_val = env.argStack.pop_num (); env.clear_args (); break; case OpCode_Subrs: @@ -1295,10 +1291,10 @@ struct cff1 } protected: - hb_blob_t *blob = nullptr; hb_sanitize_context_t sc; public: + hb_blob_t *blob = nullptr; const Encoding *encoding = nullptr; const Charset *charset = nullptr; const CFF1NameIndex *nameIndex = nullptr; @@ -1345,6 +1341,7 @@ struct cff1 bool get_glyph_name (hb_codepoint_t glyph, char *buf, unsigned int buf_len) const { + if (unlikely (glyph >= num_glyphs)) return false; if (unlikely (!is_valid ())) return false; if (is_CID()) return false; if (unlikely (!buf_len)) return true; @@ -1379,7 +1376,7 @@ struct cff1 if (unlikely (!len)) return false; retry: - hb_sorted_vector_t *names = glyph_names.get (); + hb_sorted_vector_t *names = glyph_names.get_acquire (); if (unlikely (!names)) { names = (hb_sorted_vector_t *) hb_calloc (sizeof (hb_sorted_vector_t), 1); @@ -1428,6 +1425,7 @@ struct cff1 } HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const; HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc index 1e757ebfba9..ed430ee59d5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.cc @@ -124,8 +124,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->x_bearing = font->em_scalef_x (param.min_x.to_real ()); - extents->width = font->em_scalef_x (param.max_x.to_real ()) - extents->x_bearing; + extents->x_bearing = roundf (param.min_x.to_real ()); + extents->width = roundf (param.max_x.to_real () - extents->x_bearing); } if (param.min_y >= param.max_y) { @@ -134,10 +134,21 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, } else { - extents->y_bearing = font->em_scalef_y (param.max_y.to_real ()); - extents->height = font->em_scalef_y (param.min_y.to_real ()) - extents->y_bearing; + extents->y_bearing = roundf (param.max_y.to_real ()); + extents->height = roundf (param.min_y.to_real () - extents->y_bearing); } + font->scale_glyph_extents (extents); + + return true; +} + +bool OT::cff2::accelerator_t::paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const +{ + funcs->push_clip_glyph (data, glyph, font); + funcs->color (data, true, foreground); + funcs->pop_clip (data); + return true; } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh index 7e1a3d0dba1..bfbc26b96ec 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cff2-table.hh @@ -30,6 +30,7 @@ #include "hb-ot-cff-common.hh" #include "hb-subset-cff2.hh" #include "hb-draw.hh" +#include "hb-paint.hh" namespace CFF { @@ -56,7 +57,7 @@ struct CFF2FDSelect unsigned int size = src.get_size (num_glyphs); CFF2FDSelect *dest = c->allocate_size (size); if (unlikely (!dest)) return_trace (false); - memcpy (dest, &src, size); + hb_memcpy (dest, &src, size); return_trace (true); } @@ -124,7 +125,7 @@ struct CFF2VariationStore unsigned int size_ = varStore->get_size (); CFF2VariationStore *dest = c->allocate_size (size_); if (unlikely (!dest)) return_trace (false); - memcpy (dest, varStore, size_); + hb_memcpy (dest, varStore, size_); return_trace (true); } @@ -282,9 +283,6 @@ struct cff2_private_dict_opset_t : dict_opset_t case OpCode_BlueFuzz: case OpCode_ExpansionFactor: case OpCode_LanguageGroup: - val.single_val = env.argStack.pop_num (); - env.clear_args (); - break; case OpCode_BlueValues: case OpCode_OtherBlues: case OpCode_FamilyBlues: @@ -483,13 +481,18 @@ struct cff2 blob = nullptr; } + hb_map_t *create_glyph_to_sid_map () const + { + return nullptr; + } + bool is_valid () const { return blob; } protected: - hb_blob_t *blob = nullptr; hb_sanitize_context_t sc; public: + hb_blob_t *blob = nullptr; cff2_top_dict_values_t topDict; const CFF2Subrs *globalSubrs = nullptr; const CFF2VariationStore *varStore = nullptr; @@ -511,6 +514,7 @@ struct cff2 HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; + HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const; HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; }; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh index 4b6e542fb87..4a7a693e201 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-cmap-table.hh @@ -31,6 +31,7 @@ #include "hb-ot-shaper-arabic-pua.hh" #include "hb-open-type.hh" #include "hb-set.hh" +#include "hb-cache.hh" /* * cmap -- Character to Glyph Index Mapping @@ -909,7 +910,7 @@ struct DefaultUVS : SortedArray32Of hb_codepoint_t first = arrayZ[i].startUnicodeValue; hb_codepoint_t last = hb_min ((hb_codepoint_t) (first + arrayZ[i].additionalCount), (hb_codepoint_t) HB_UNICODE_MAX); - out->add_range (first, hb_min (last, 0x10FFFFu)); + out->add_range (first, last); } } @@ -925,37 +926,75 @@ struct DefaultUVS : SortedArray32Of if (unlikely (!c->copy (len))) return nullptr; unsigned init_len = c->length (); - hb_codepoint_t lastCode = HB_MAP_VALUE_INVALID; - int count = -1; - - for (const UnicodeValueRange& _ : as_array ()) + if (this->len > unicodes->get_population () * hb_bit_storage ((unsigned) this->len)) { - for (const unsigned addcnt : hb_range ((unsigned) _.additionalCount + 1)) + hb_codepoint_t start = HB_SET_VALUE_INVALID; + hb_codepoint_t end = HB_SET_VALUE_INVALID; + + for (hb_codepoint_t u = HB_SET_VALUE_INVALID; + unicodes->next (&u);) { - unsigned curEntry = (unsigned) _.startUnicodeValue + addcnt; - if (!unicodes->has (curEntry)) continue; - count += 1; - if (lastCode == HB_MAP_VALUE_INVALID) - lastCode = curEntry; - else if (lastCode + count != curEntry) + if (!as_array ().bsearch (u)) + continue; + if (start == HB_SET_VALUE_INVALID) + { + start = u; + end = start - 1; + } + if (end + 1 != u || end - start == 255) { UnicodeValueRange rec; - rec.startUnicodeValue = lastCode; - rec.additionalCount = count - 1; + rec.startUnicodeValue = start; + rec.additionalCount = end - start; c->copy (rec); - - lastCode = curEntry; - count = 0; + start = u; } + end = u; + } + if (start != HB_SET_VALUE_INVALID) + { + UnicodeValueRange rec; + rec.startUnicodeValue = start; + rec.additionalCount = end - start; + c->copy (rec); } - } - if (lastCode != HB_MAP_VALUE_INVALID) + } + else { - UnicodeValueRange rec; - rec.startUnicodeValue = lastCode; - rec.additionalCount = count; - c->copy (rec); + hb_codepoint_t lastCode = HB_SET_VALUE_INVALID; + int count = -1; + + for (const UnicodeValueRange& _ : *this) + { + hb_codepoint_t curEntry = (hb_codepoint_t) (_.startUnicodeValue - 1); + hb_codepoint_t end = curEntry + _.additionalCount + 2; + + for (; unicodes->next (&curEntry) && curEntry < end;) + { + count += 1; + if (lastCode == HB_SET_VALUE_INVALID) + lastCode = curEntry; + else if (lastCode + count != curEntry) + { + UnicodeValueRange rec; + rec.startUnicodeValue = lastCode; + rec.additionalCount = count - 1; + c->copy (rec); + + lastCode = curEntry; + count = 0; + } + } + } + + if (lastCode != HB_MAP_VALUE_INVALID) + { + UnicodeValueRange rec; + rec.startUnicodeValue = lastCode; + rec.additionalCount = count; + c->copy (rec); + } } if (c->length () - init_len == 0) @@ -1376,7 +1415,7 @@ struct CmapSubtable switch (format) { case 4: return u.format4.serialize (c, it); case 12: return u.format12.serialize (c, it); - case 14: return u.format14.serialize (c, plan->unicodes, plan->glyphs_requested, plan->glyph_map, base); + case 14: return u.format14.serialize (c, &plan->unicodes, &plan->glyphs_requested, plan->glyph_map, base); default: return; } } @@ -1474,19 +1513,67 @@ struct EncodingRecord DEFINE_SIZE_STATIC (8); }; +struct cmap; + struct SubtableUnicodesCache { private: - const void* base; - hb_hashmap_t> cached_unicodes; + hb_blob_ptr_t base_blob; + const char* base; + hb_hashmap_t> cached_unicodes; public: + + static SubtableUnicodesCache* create (hb_blob_ptr_t source_table) + { + SubtableUnicodesCache* cache = + (SubtableUnicodesCache*) hb_malloc (sizeof(SubtableUnicodesCache)); + new (cache) SubtableUnicodesCache (source_table); + return cache; + } + + static void destroy (void* value) { + if (!value) return; + + SubtableUnicodesCache* cache = (SubtableUnicodesCache*) value; + cache->~SubtableUnicodesCache (); + hb_free (cache); + } + SubtableUnicodesCache(const void* cmap_base) - : base(cmap_base), cached_unicodes() {} + : base_blob(), + base ((const char*) cmap_base), + cached_unicodes () + {} + + SubtableUnicodesCache(hb_blob_ptr_t base_blob_) + : base_blob(base_blob_), + base ((const char *) base_blob.get()), + cached_unicodes () + {} + + ~SubtableUnicodesCache() + { + base_blob.destroy (); + } - hb_set_t* set_for (const EncodingRecord* record) + bool same_base(const void* other) const { - if (!cached_unicodes.has ((intptr_t) record)) + return other == (const void*) base; + } + + const hb_set_t* set_for (const EncodingRecord* record, + SubtableUnicodesCache& mutable_cache) const + { + if (cached_unicodes.has ((unsigned) ((const char *) record - base))) + return cached_unicodes.get ((unsigned) ((const char *) record - base)); + + return mutable_cache.set_for (record); + } + + const hb_set_t* set_for (const EncodingRecord* record) + { + if (!cached_unicodes.has ((unsigned) ((const char *) record - base))) { hb_set_t *s = hb_set_create (); if (unlikely (s->in_error ())) @@ -1494,12 +1581,12 @@ struct SubtableUnicodesCache { (base+record->subtable).collect_unicodes (s); - if (unlikely (!cached_unicodes.set ((intptr_t) record, hb::unique_ptr {s}))) + if (unlikely (!cached_unicodes.set ((unsigned) ((const char *) record - base), hb::unique_ptr {s}))) return hb_set_get_empty (); return s; } - return cached_unicodes.get ((intptr_t) record); + return cached_unicodes.get ((unsigned) ((const char *) record - base)); } }; @@ -1523,13 +1610,30 @@ struct cmap { static constexpr hb_tag_t tableTag = HB_OT_TAG_cmap; + + static SubtableUnicodesCache* create_filled_cache(hb_blob_ptr_t source_table) { + const cmap* cmap = source_table.get(); + auto it = + + hb_iter (cmap->encodingRecord) + | hb_filter ([&](const EncodingRecord& _) { + return cmap::filter_encoding_records_for_subset (cmap, _); + }) + ; + + SubtableUnicodesCache* cache = SubtableUnicodesCache::create(source_table); + for (const EncodingRecord& _ : it) + cache->set_for(&_); // populate the cache for this encoding record. + + return cache; + } + template bool serialize (hb_serialize_context_t *c, Iterator it, EncodingRecIter encodingrec_iter, const void *base, - const hb_subset_plan_t *plan, + hb_subset_plan_t *plan, bool drop_format_4 = false) { if (unlikely (!c->extend_min ((*this)))) return false; @@ -1538,7 +1642,14 @@ struct cmap unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0; auto snap = c->snapshot (); - SubtableUnicodesCache unicodes_cache (base); + SubtableUnicodesCache local_unicodes_cache (base); + const SubtableUnicodesCache* unicodes_cache = &local_unicodes_cache; + + if (plan->accelerator && + plan->accelerator->cmap_cache && + plan->accelerator->cmap_cache->same_base (base)) + unicodes_cache = plan->accelerator->cmap_cache; + for (const EncodingRecord& _ : encodingrec_iter) { if (c->in_error ()) @@ -1547,7 +1658,7 @@ struct cmap unsigned format = (base+_.subtable).u.format; if (format != 4 && format != 12 && format != 14) continue; - hb_set_t* unicodes_set = unicodes_cache.set_for (&_); + const hb_set_t* unicodes_set = unicodes_cache->set_for (&_, local_unicodes_cache); if (!drop_format_4 && format == 4) { @@ -1566,7 +1677,13 @@ struct cmap else if (format == 12) { - if (_can_drop (_, *unicodes_set, base, unicodes_cache, + it | hb_map (hb_first), encodingrec_iter)) continue; + if (_can_drop (_, + *unicodes_set, + base, + *unicodes_cache, + local_unicodes_cache, + + it | hb_map (hb_first), encodingrec_iter)) + continue; c->copy (_, + it | hb_filter (*unicodes_set, hb_first), 12u, base, plan, &format12objidx); } else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx); @@ -1585,7 +1702,8 @@ struct cmap bool _can_drop (const EncodingRecord& cmap12, const hb_set_t& cmap12_unicodes, const void* base, - SubtableUnicodesCache& unicodes_cache, + const SubtableUnicodesCache& unicodes_cache, + SubtableUnicodesCache& local_unicodes_cache, Iterator subset_unicodes, EncodingRecordIterator encoding_records) { @@ -1616,7 +1734,7 @@ struct cmap || (base+_.subtable).get_language() != target_language) continue; - hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_); + const hb_set_t* sibling_unicodes = unicodes_cache.set_for (&_, local_unicodes_cache); auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes); auto sibling = + subset_unicodes | hb_filter (*sibling_unicodes); @@ -1653,17 +1771,9 @@ struct cmap auto encodingrec_iter = + hb_iter (encodingRecord) - | hb_filter ([&] (const EncodingRecord& _) - { - if ((_.platformID == 0 && _.encodingID == 3) || - (_.platformID == 0 && _.encodingID == 4) || - (_.platformID == 3 && _.encodingID == 1) || - (_.platformID == 3 && _.encodingID == 10) || - (this + _.subtable).u.format == 14) - return true; - - return false; - }) + | hb_filter ([&](const EncodingRecord& _) { + return cmap::filter_encoding_records_for_subset (this, _); + }) ; if (unlikely (!encodingrec_iter.len ())) return_trace (false); @@ -1692,7 +1802,11 @@ struct cmap { return (_.second != HB_MAP_VALUE_INVALID); }) ; - return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan)); + return_trace (cmap_prime->serialize (c->serializer, + it, + encodingrec_iter, + this, + c->plan)); } const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const @@ -1728,6 +1842,8 @@ struct cmap struct accelerator_t { + using cache_t = hb_cache_t<21, 16, 8, true>; + accelerator_t (hb_face_t *face) { this->table = hb_sanitize_context_t ().reference_table (face); @@ -1782,26 +1898,43 @@ struct cmap } ~accelerator_t () { this->table.destroy (); } + inline bool _cached_get (hb_codepoint_t unicode, + hb_codepoint_t *glyph, + cache_t *cache) const + { + unsigned v; + if (cache && cache->get (unicode, &v)) + { + *glyph = v; + return true; + } + bool ret = this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); + + if (cache && ret) + cache->set (unicode, *glyph); + return ret; + } + bool get_nominal_glyph (hb_codepoint_t unicode, - hb_codepoint_t *glyph) const + hb_codepoint_t *glyph, + cache_t *cache = nullptr) const { - if (unlikely (!this->get_glyph_funcZ)) return false; - return this->get_glyph_funcZ (this->get_glyph_data, unicode, glyph); + if (unlikely (!this->get_glyph_funcZ)) return 0; + return _cached_get (unicode, glyph, cache); } + unsigned int get_nominal_glyphs (unsigned int count, const hb_codepoint_t *first_unicode, unsigned int unicode_stride, hb_codepoint_t *first_glyph, - unsigned int glyph_stride) const + unsigned int glyph_stride, + cache_t *cache = nullptr) const { if (unlikely (!this->get_glyph_funcZ)) return 0; - hb_cmap_get_glyph_func_t get_glyph_funcZ = this->get_glyph_funcZ; - const void *get_glyph_data = this->get_glyph_data; - unsigned int done; for (done = 0; - done < count && get_glyph_funcZ (get_glyph_data, *first_unicode, first_glyph); + done < count && _cached_get (*first_unicode, first_glyph, cache); done++) { first_unicode = &StructAtOffsetUnaligned (first_unicode, unicode_stride); @@ -1812,7 +1945,8 @@ struct cmap bool get_variation_glyph (hb_codepoint_t unicode, hb_codepoint_t variation_selector, - hb_codepoint_t *glyph) const + hb_codepoint_t *glyph, + cache_t *cache = nullptr) const { switch (this->subtable_uvs->get_glyph_variant (unicode, variation_selector, @@ -1823,7 +1957,7 @@ struct cmap case GLYPH_VARIANT_USE_DEFAULT: break; } - return get_nominal_glyph (unicode, glyph); + return get_nominal_glyph (unicode, glyph, cache); } void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const @@ -1928,6 +2062,19 @@ struct cmap encodingRecord.sanitize (c, this)); } + private: + + static bool filter_encoding_records_for_subset(const cmap* cmap, + const EncodingRecord& _) + { + return + (_.platformID == 0 && _.encodingID == 3) || + (_.platformID == 0 && _.encodingID == 4) || + (_.platformID == 3 && _.encodingID == 1) || + (_.platformID == 3 && _.encodingID == 10) || + (cmap + _.subtable).u.format == 14; + } + protected: HBUINT16 version; /* Table version number (0). */ SortedArray16Of diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc index 5b45dbcd9fc..ef46fe5429a 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.cc @@ -31,11 +31,11 @@ #include "hb-ot.h" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-colr-table.hh" -#include "hb-ot-color-cpal-table.hh" -#include "hb-ot-color-sbix-table.hh" -#include "hb-ot-color-svg-table.hh" +#include "OT/Color/CBDT/CBDT.hh" +#include "OT/Color/COLR/COLR.hh" +#include "OT/Color/CPAL/CPAL.hh" +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/svg/svg.hh" /** @@ -61,7 +61,7 @@ * * Tests whether a face includes a `CPAL` color-palette table. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 2.1.0 */ @@ -167,6 +167,10 @@ hb_ot_color_palette_get_flags (hb_face_t *face, * for allocating a buffer of suitable size before calling * hb_ot_color_palette_get_colors() a second time. * + * The RGBA values in the palette are unpremultiplied. See the + * OpenType spec [CPAL](https://learn.microsoft.com/en-us/typography/opentype/spec/cpal) + * section for details. + * * Return value: the total number of colors in the palette * * Since: 2.1.0 @@ -190,16 +194,53 @@ hb_ot_color_palette_get_colors (hb_face_t *face, * hb_ot_color_has_layers: * @face: #hb_face_t to work upon * - * Tests whether a face includes any `COLR` color layers. + * Tests whether a face includes a `COLR` table + * with data according to COLRv0. * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 2.1.0 */ hb_bool_t hb_ot_color_has_layers (hb_face_t *face) { - return face->table.COLR->has_data (); + return face->table.COLR->has_v0_data (); +} + +/** + * hb_ot_color_has_paint: + * @face: #hb_face_t to work upon + * + * Tests where a face includes a `COLR` table + * with data according to COLRv1. + * + * Return value: `true` if data found, `false` otherwise + * + * Since: 7.0.0 + */ +hb_bool_t +hb_ot_color_has_paint (hb_face_t *face) +{ + return face->table.COLR->has_v1_data (); +} + +/** + * hb_ot_color_glyph_has_paint: + * @face: #hb_face_t to work upon + * @glyph: The glyph index to query + * + * Tests where a face includes COLRv1 paint + * data for @glyph. + * + * Return value: `true` if data found, `false` otherwise + * + * Since: 7.0.0 + */ +hb_bool_t +hb_ot_color_glyph_has_paint (hb_face_t *face, + hb_codepoint_t glyph) +{ + return face->table.COLR->has_paint_for_glyph (glyph); } /** @@ -239,7 +280,7 @@ hb_ot_color_glyph_get_layers (hb_face_t *face, * * Tests whether a face includes any `SVG` glyph images. * - * Return value: %true if data found, %false otherwise. + * Return value: `true` if data found, `false` otherwise. * * Since: 2.1.0 */ @@ -279,7 +320,7 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph) * * Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables). * - * Return value: %true if data found, %false otherwise + * Return value: `true` if data found, `false` otherwise * * Since: 2.1.0 */ @@ -295,8 +336,8 @@ hb_ot_color_has_png (hb_face_t *face) * @glyph: a glyph index * * Fetches the PNG image for a glyph. This function takes a font object, not a face object, - * as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font - * object. If UPEM is unset, the blob returned will be the largest PNG available. + * as input. To get an optimally sized PNG blob, the PPEM values must be set on the @font + * object. If PPEM is unset, the blob returned will be the largest PNG available. * * If the glyph has no PNG image, the singleton empty blob is returned. * diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h index ff659c7a458..7fa810bd96f 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-color.h @@ -102,6 +102,10 @@ hb_ot_color_has_layers (hb_face_t *face); * * Pairs of glyph and color index. * + * A color index of 0xFFFF does not refer to a palette + * color, but indicates that the foreground color should + * be used. + * * Since: 2.1.0 **/ typedef struct hb_ot_color_layer_t { @@ -116,6 +120,15 @@ hb_ot_color_glyph_get_layers (hb_face_t *face, unsigned int *layer_count, /* IN/OUT. May be NULL. */ hb_ot_color_layer_t *layers /* OUT. May be NULL. */); +/* COLRv1 */ + +HB_EXTERN hb_bool_t +hb_ot_color_has_paint (hb_face_t *face); + +HB_EXTERN hb_bool_t +hb_ot_color_glyph_has_paint (hb_face_t *face, + hb_codepoint_t glyph); + /* * SVG */ diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h b/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h index da205d6713d..24656af53bb 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-deprecated.h @@ -67,26 +67,30 @@ HB_BEGIN_DECLS /* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */ -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t +HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) +HB_EXTERN hb_bool_t hb_ot_layout_table_choose_script (hb_face_t *face, hb_tag_t table_tag, const hb_tag_t *script_tags, unsigned int *script_index, hb_tag_t *chosen_script); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_script_select_language) hb_bool_t +HB_DEPRECATED_FOR (hb_ot_layout_script_select_language) +HB_EXTERN hb_bool_t hb_ot_layout_script_find_language (hb_face_t *face, hb_tag_t table_tag, unsigned int script_index, hb_tag_t language_tag, unsigned int *language_index); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) void +HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) +HB_EXTERN void hb_ot_tags_from_script (hb_script_t script, hb_tag_t *script_tag_1, hb_tag_t *script_tag_2); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) hb_tag_t +HB_DEPRECATED_FOR (hb_ot_tags_from_script_and_language) +HB_EXTERN hb_tag_t hb_ot_tag_from_language (hb_language_t language); @@ -121,13 +125,15 @@ typedef struct hb_ot_var_axis_t { float max_value; } hb_ot_var_axis_t; -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_get_axis_infos) unsigned int +HB_DEPRECATED_FOR (hb_ot_var_get_axis_infos) +HB_EXTERN unsigned int hb_ot_var_get_axes (hb_face_t *face, unsigned int start_offset, unsigned int *axes_count /* IN/OUT */, hb_ot_var_axis_t *axes_array /* OUT */); -HB_EXTERN HB_DEPRECATED_FOR (hb_ot_var_find_axis_info) hb_bool_t +HB_DEPRECATED_FOR (hb_ot_var_find_axis_info) +HB_EXTERN hb_bool_t hb_ot_var_find_axis (hb_face_t *face, hb_tag_t axis_tag, unsigned int *axis_index, diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh index c05034b3bb5..c9da36c1bb5 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-face-table-list.hh @@ -56,9 +56,9 @@ HB_OT_CORE_TABLE (OT, maxp) #if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT) HB_OT_ACCELERATOR (OT, cmap) #endif -HB_OT_TABLE (OT, hhea) +HB_OT_CORE_TABLE (OT, hhea) HB_OT_ACCELERATOR (OT, hmtx) -HB_OT_TABLE (OT, OS2) +HB_OT_CORE_TABLE (OT, OS2) #if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE) HB_OT_ACCELERATOR (OT, post) #endif @@ -66,7 +66,7 @@ HB_OT_ACCELERATOR (OT, post) HB_OT_ACCELERATOR (OT, name) #endif #ifndef HB_NO_STYLE -HB_OT_TABLE (OT, STAT) +HB_OT_CORE_TABLE (OT, STAT) #endif #ifndef HB_NO_META HB_OT_ACCELERATOR (OT, meta) @@ -74,9 +74,9 @@ HB_OT_ACCELERATOR (OT, meta) /* Vertical layout. */ #ifndef HB_NO_VERTICAL -HB_OT_TABLE (OT, vhea) +HB_OT_CORE_TABLE (OT, vhea) HB_OT_ACCELERATOR (OT, vmtx) -HB_OT_TABLE (OT, VORG) +HB_OT_CORE_TABLE (OT, VORG) #endif /* TrueType outlines. */ @@ -91,15 +91,15 @@ HB_OT_ACCELERATOR (OT, cff2) /* OpenType variations. */ #ifndef HB_NO_VAR -HB_OT_TABLE (OT, fvar) -HB_OT_TABLE (OT, avar) +HB_OT_CORE_TABLE (OT, fvar) +HB_OT_CORE_TABLE (OT, avar) HB_OT_ACCELERATOR (OT, gvar) -HB_OT_TABLE (OT, MVAR) +HB_OT_CORE_TABLE (OT, MVAR) #endif /* Legacy kern. */ #ifndef HB_NO_OT_KERN -HB_OT_TABLE (OT, kern) +HB_OT_CORE_TABLE (OT, kern) #endif /* OpenType shaping. */ @@ -107,12 +107,12 @@ HB_OT_TABLE (OT, kern) HB_OT_ACCELERATOR (OT, GDEF) HB_OT_ACCELERATOR (OT, GSUB) HB_OT_ACCELERATOR (OT, GPOS) -//HB_OT_TABLE (OT, JSTF) +//HB_OT_CORE_TABLE (OT, JSTF) #endif /* OpenType baseline. */ #ifndef HB_NO_BASE -HB_OT_TABLE (OT, BASE) +HB_OT_CORE_TABLE (OT, BASE) #endif /* AAT shaping. */ @@ -129,8 +129,8 @@ HB_OT_TABLE (AAT, feat) /* OpenType color fonts. */ #ifndef HB_NO_COLOR -HB_OT_TABLE (OT, COLR) -HB_OT_TABLE (OT, CPAL) +HB_OT_CORE_TABLE (OT, COLR) +HB_OT_CORE_TABLE (OT, CPAL) HB_OT_ACCELERATOR (OT, CBDT) HB_OT_ACCELERATOR (OT, sbix) HB_OT_ACCELERATOR (OT, SVG) @@ -138,7 +138,7 @@ HB_OT_ACCELERATOR (OT, SVG) /* OpenType math. */ #ifndef HB_NO_MATH -HB_OT_TABLE (OT, MATH) +HB_OT_CORE_TABLE (OT, MATH) #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc index 5ef8df43ce7..2243ee02874 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-face.cc @@ -35,9 +35,9 @@ #include "hb-ot-meta-table.hh" #include "hb-ot-name-table.hh" #include "hb-ot-post-table.hh" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-sbix-table.hh" -#include "hb-ot-color-svg-table.hh" +#include "OT/Color/CBDT/CBDT.hh" +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/svg/svg.hh" #include "hb-ot-layout-gdef-table.hh" #include "hb-ot-layout-gsub-table.hh" #include "hb-ot-layout-gpos-table.hh" diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc index 2f3d4759118..f1e882ed938 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-font.cc @@ -34,18 +34,20 @@ #include "hb-font.hh" #include "hb-machinery.hh" #include "hb-ot-face.hh" +#include "hb-outline.hh" #include "hb-ot-cmap-table.hh" #include "hb-ot-glyf-table.hh" #include "hb-ot-cff1-table.hh" #include "hb-ot-cff2-table.hh" #include "hb-ot-hmtx-table.hh" -#include "hb-ot-os2-table.hh" #include "hb-ot-post-table.hh" #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-vorg-table.hh" -#include "hb-ot-color-cbdt-table.hh" -#include "hb-ot-color-sbix-table.hh" +#include "OT/Color/CBDT/CBDT.hh" +#include "OT/Color/COLR/COLR.hh" +#include "OT/Color/sbix/sbix.hh" +#include "OT/Color/svg/svg.hh" /** @@ -59,13 +61,20 @@ * never need to call these functions directly. **/ +using hb_ot_font_cmap_cache_t = hb_cache_t<21, 16, 8, true>; +using hb_ot_font_advance_cache_t = hb_cache_t<24, 16, 8, true>; + +static hb_user_data_key_t hb_ot_font_cmap_cache_user_data_key; + struct hb_ot_font_t { const hb_ot_face_t *ot_face; + hb_ot_font_cmap_cache_t *cmap_cache; + /* h_advance caching */ mutable hb_atomic_int_t cached_coords_serial; - mutable hb_atomic_ptr_t advance_cache; + mutable hb_atomic_ptr_t advance_cache; }; static hb_ot_font_t * @@ -77,6 +86,33 @@ _hb_ot_font_create (hb_font_t *font) ot_font->ot_face = &font->face->table; + // retry: + auto *cmap_cache = (hb_ot_font_cmap_cache_t *) hb_face_get_user_data (font->face, + &hb_ot_font_cmap_cache_user_data_key); + if (!cmap_cache) + { + cmap_cache = (hb_ot_font_cmap_cache_t *) hb_malloc (sizeof (hb_ot_font_cmap_cache_t)); + if (unlikely (!cmap_cache)) goto out; + cmap_cache->init (); + if (unlikely (!hb_face_set_user_data (font->face, + &hb_ot_font_cmap_cache_user_data_key, + cmap_cache, + hb_free, + false))) + { + hb_free (cmap_cache); + cmap_cache = nullptr; + /* Normally we would retry here, but that would + * infinite-loop if the face is the empty-face. + * Just let it go and this font will be uncached if it + * happened to collide with another thread creating the + * cache at the same time. */ + // goto retry; + } + } + out: + ot_font->cmap_cache = cmap_cache; + return ot_font; } @@ -86,11 +122,7 @@ _hb_ot_font_destroy (void *font_data) hb_ot_font_t *ot_font = (hb_ot_font_t *) font_data; auto *cache = ot_font->advance_cache.get_relaxed (); - if (cache) - { - cache->fini (); - hb_free (cache); - } + hb_free (cache); hb_free (ot_font); } @@ -104,7 +136,7 @@ hb_ot_get_nominal_glyph (hb_font_t *font HB_UNUSED, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - return ot_face->cmap->get_nominal_glyph (unicode, glyph); + return ot_face->cmap->get_nominal_glyph (unicode, glyph, ot_font->cmap_cache); } static unsigned int @@ -121,7 +153,8 @@ hb_ot_get_nominal_glyphs (hb_font_t *font HB_UNUSED, const hb_ot_face_t *ot_face = ot_font->ot_face; return ot_face->cmap->get_nominal_glyphs (count, first_unicode, unicode_stride, - first_glyph, glyph_stride); + first_glyph, glyph_stride, + ot_font->cmap_cache); } static hb_bool_t @@ -134,7 +167,9 @@ hb_ot_get_variation_glyph (hb_font_t *font HB_UNUSED, { const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; - return ot_face->cmap->get_variation_glyph (unicode, variation_selector, glyph); + return ot_face->cmap->get_variation_glyph (unicode, + variation_selector, glyph, + ot_font->cmap_cache); } static void @@ -146,12 +181,15 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, unsigned advance_stride, void *user_data HB_UNUSED) { + const hb_ot_font_t *ot_font = (const hb_ot_font_t *) font_data; const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx; + hb_position_t *orig_first_advance = first_advance; + #ifndef HB_NO_VAR - const OT::HVARVVAR &HVAR = *hmtx.var_table; + const OT::HVAR &HVAR = *hmtx.var_table; const OT::VariationStore &varStore = &HVAR + HVAR.varStore; OT::VariationStore::cache_t *varStore_cache = font->num_coords * count >= 128 ? varStore.create_cache () : nullptr; @@ -161,14 +199,14 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, bool use_cache = false; #endif - hb_advance_cache_t *cache = nullptr; + hb_ot_font_advance_cache_t *cache = nullptr; if (use_cache) { retry: - cache = ot_font->advance_cache.get (); + cache = ot_font->advance_cache.get_acquire (); if (unlikely (!cache)) { - cache = (hb_advance_cache_t *) hb_malloc (sizeof (hb_advance_cache_t)); + cache = (hb_ot_font_advance_cache_t *) hb_malloc (sizeof (hb_ot_font_advance_cache_t)); if (unlikely (!cache)) { use_cache = false; @@ -181,7 +219,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, hb_free (cache); goto retry; } - ot_font->cached_coords_serial.set (font->serial_coords); + ot_font->cached_coords_serial.set_release (font->serial_coords); } } out: @@ -190,17 +228,17 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, { for (unsigned int i = 0; i < count; i++) { - *first_advance = font->em_scale_x (hmtx.get_advance (*first_glyph, font, varStore_cache)); + *first_advance = font->em_scale_x (hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache)); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } else { /* Use cache. */ - if (ot_font->cached_coords_serial.get () != (int) font->serial_coords) + if (ot_font->cached_coords_serial.get_acquire () != (int) font->serial_coords) { ot_font->advance_cache->init (); - ot_font->cached_coords_serial.set (font->serial_coords); + ot_font->cached_coords_serial.set_release (font->serial_coords); } for (unsigned int i = 0; i < count; i++) @@ -211,7 +249,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, v = cv; else { - v = hmtx.get_advance (*first_glyph, font, varStore_cache); + v = hmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache); ot_font->advance_cache->set (*first_glyph, v); } *first_advance = font->em_scale_x (v); @@ -223,6 +261,18 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, #ifndef HB_NO_VAR OT::VariationStore::destroy_cache (varStore_cache); #endif + + if (font->x_strength && !font->embolden_in_place) + { + /* Emboldening. */ + hb_position_t x_strength = font->x_scale >= 0 ? font->x_strength : -font->x_strength; + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? x_strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } #ifndef HB_NO_VERTICAL @@ -239,10 +289,12 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, const hb_ot_face_t *ot_face = ot_font->ot_face; const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; + hb_position_t *orig_first_advance = first_advance; + if (vmtx.has_data ()) { #ifndef HB_NO_VAR - const OT::HVARVVAR &VVAR = *vmtx.var_table; + const OT::VVAR &VVAR = *vmtx.var_table; const OT::VariationStore &varStore = &VVAR + VVAR.varStore; OT::VariationStore::cache_t *varStore_cache = font->num_coords ? varStore.create_cache () : nullptr; #else @@ -251,7 +303,7 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, for (unsigned int i = 0; i < count; i++) { - *first_advance = font->em_scale_y (-(int) vmtx.get_advance (*first_glyph, font, varStore_cache)); + *first_advance = font->em_scale_y (-(int) vmtx.get_advance_with_var_unscaled (*first_glyph, font, varStore_cache)); first_glyph = &StructAtOffsetUnaligned (first_glyph, glyph_stride); first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } @@ -273,6 +325,18 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); } } + + if (font->y_strength && !font->embolden_in_place) + { + /* Emboldening. */ + hb_position_t y_strength = font->y_scale >= 0 ? font->y_strength : -font->y_strength; + first_advance = orig_first_advance; + for (unsigned int i = 0; i < count; i++) + { + *first_advance += *first_advance ? y_strength : 0; + first_advance = &StructAtOffsetUnaligned (first_advance, advance_stride); + } + } } #endif @@ -293,17 +357,28 @@ hb_ot_get_glyph_v_origin (hb_font_t *font, const OT::VORG &VORG = *ot_face->VORG; if (VORG.has_data ()) { - *y = font->em_scale_y (VORG.get_y_origin (glyph)); + float delta = 0; + +#ifndef HB_NO_VAR + const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; + const OT::VVAR &VVAR = *vmtx.var_table; + if (font->num_coords) + VVAR.get_vorg_delta_unscaled (glyph, + font->coords, font->num_coords, + &delta); +#endif + + *y = font->em_scalef_y (VORG.get_y_origin (glyph) + delta); return true; } hb_glyph_extents_t extents = {0}; if (ot_face->glyf->get_extents (font, glyph, &extents)) { - if (ot_face->vmtx->has_data ()) + const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; + int tsb = 0; + if (vmtx.get_leading_bearing_with_var_unscaled (font, glyph, &tsb)) { - const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - hb_position_t tsb = vmtx.get_side_bearing (font, glyph); *y = extents.y_bearing + font->em_scale_y (tsb); return true; } @@ -336,17 +411,17 @@ hb_ot_get_glyph_extents (hb_font_t *font, #if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) if (ot_face->sbix->get_extents (font, glyph, extents)) return true; + if (ot_face->CBDT->get_extents (font, glyph, extents)) return true; +#endif +#if !defined(HB_NO_COLOR) + if (ot_face->COLR->get_extents (font, glyph, extents)) return true; #endif if (ot_face->glyf->get_extents (font, glyph, extents)) return true; #ifndef HB_NO_OT_FONT_CFF if (ot_face->cff1->get_extents (font, glyph, extents)) return true; if (ot_face->cff2->get_extents (font, glyph, extents)) return true; #endif -#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR) - if (ot_face->CBDT->get_extents (font, glyph, extents)) return true; -#endif - // TODO Hook up side-bearings variations. return false; } @@ -391,9 +466,16 @@ hb_ot_get_font_h_extents (hb_font_t *font, hb_font_extents_t *metrics, void *user_data HB_UNUSED) { - return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && - _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && - _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); + bool ret = _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) && + _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); + + /* Embolden */ + int y_shift = font->y_strength; + if (font->y_scale < 0) y_shift = -y_shift; + metrics->ascender += y_shift; + + return ret; } #ifndef HB_NO_VERTICAL @@ -411,17 +493,62 @@ hb_ot_get_font_v_extents (hb_font_t *font, #ifndef HB_NO_DRAW static void -hb_ot_get_glyph_shape (hb_font_t *font, - void *font_data HB_UNUSED, - hb_codepoint_t glyph, - hb_draw_funcs_t *draw_funcs, void *draw_data, - void *user_data) +hb_ot_draw_glyph (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data) { - hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); - if (font->face->table.glyf->get_path (font, glyph, draw_session)) return; + bool embolden = font->x_strength || font->y_strength; + hb_outline_t outline; + + { // Need draw_session to be destructed before emboldening. + hb_draw_session_t draw_session (embolden ? hb_outline_recording_pen_get_funcs () : draw_funcs, + embolden ? &outline : draw_data, font->slant_xy); + if (!font->face->table.glyf->get_path (font, glyph, draw_session)) #ifndef HB_NO_CFF - if (font->face->table.cff1->get_path (font, glyph, draw_session)) return; - if (font->face->table.cff2->get_path (font, glyph, draw_session)) return; + if (!font->face->table.cff1->get_path (font, glyph, draw_session)) + if (!font->face->table.cff2->get_path (font, glyph, draw_session)) +#endif + {} + } + + if (embolden) + { + float x_shift = font->embolden_in_place ? 0 : (float) font->x_strength / 2; + float y_shift = (float) font->y_strength / 2; + if (font->x_scale < 0) x_shift = -x_shift; + if (font->y_scale < 0) y_shift = -y_shift; + outline.embolden (font->x_strength, font->y_strength, + x_shift, y_shift); + + outline.replay (draw_funcs, draw_data); + } +} +#endif + +#ifndef HB_NO_PAINT +static void +hb_ot_paint_glyph (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + hb_paint_funcs_t *paint_funcs, void *paint_data, + unsigned int palette, + hb_color_t foreground, + void *user_data) +{ +#ifndef HB_NO_COLOR + if (font->face->table.COLR->paint_glyph (font, glyph, paint_funcs, paint_data, palette, foreground)) return; + if (font->face->table.SVG->paint_glyph (font, glyph, paint_funcs, paint_data)) return; +#ifndef HB_NO_OT_FONT_BITMAP + if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return; + if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return; +#endif +#endif + if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; +#ifndef HB_NO_CFF + if (font->face->table.cff1->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; + if (font->face->table.cff2->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return; #endif } #endif @@ -449,7 +576,11 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_tface->table.glyf->get_side_bearing_var (font, glyph, is_vertical); + return font->face->table.glyf->get_leading_bearing_with_var_unscaled (font, glyph, is_vertical, lsb); } unsigned -_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) +_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical) { - return font->face->table.glyf->get_advance_var (font, glyph, is_vertical); + return font->face->table.glyf->get_advance_with_var_unscaled (font, glyph, is_vertical); } #endif diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh index 84154467ed1..9346641ac35 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hdmx-table.hh @@ -156,6 +156,7 @@ struct hdmx TRACE_SANITIZE (this); return_trace (c->check_struct (this) && !hb_unsigned_mul_overflows (numRecords, sizeDeviceRecord) && + min_size + numRecords * sizeDeviceRecord > numRecords * sizeDeviceRecord && sizeDeviceRecord >= DeviceRecord::min_size && c->check_range (this, get_size ())); } diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh index c87356ae16c..22bd5fa255e 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-head-table.hh @@ -97,6 +97,7 @@ struct head * entire font as HBUINT32, then store * 0xB1B0AFBAu - sum. */ HBUINT32 magicNumber; /* Set to 0x5F0F3CF5u. */ + public: HBUINT16 flags; /* Bit 0: Baseline for font at y=0; * Bit 1: Left sidebearing point at x=0; * Bit 2: Instructions may depend on point size; @@ -141,6 +142,7 @@ struct head * encoded in the cmap subtables represent proper * support for those code points. * Bit 15: Reserved, set to 0. */ + protected: HBUINT16 unitsPerEm; /* Valid range is from 16 to 16384. This value * should be a power of 2 for fonts that have * TrueType outlines. */ @@ -148,10 +150,12 @@ struct head January 1, 1904. 64-bit integer */ LONGDATETIME modified; /* Number of seconds since 12:00 midnight, January 1, 1904. 64-bit integer */ + public: HBINT16 xMin; /* For all glyph bounding boxes. */ HBINT16 yMin; /* For all glyph bounding boxes. */ HBINT16 xMax; /* For all glyph bounding boxes. */ HBINT16 yMax; /* For all glyph bounding boxes. */ + protected: HBUINT16 macStyle; /* Bit 0: Bold (if set to 1); * Bit 1: Italic (if set to 1) * Bit 2: Underline (if set to 1) diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh index 9883df20860..4ef88053f29 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-hmtx-table.hh @@ -31,6 +31,7 @@ #include "hb-ot-maxp-table.hh" #include "hb-ot-hhea-table.hh" #include "hb-ot-var-hvar-table.hh" +#include "hb-ot-var-mvar-table.hh" #include "hb-ot-metrics.hh" /* @@ -43,11 +44,11 @@ #define HB_OT_TAG_vmtx HB_TAG('v','m','t','x') -HB_INTERNAL int -_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); +HB_INTERNAL bool +_glyf_get_leading_bearing_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical, int *lsb); HB_INTERNAL unsigned -_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); +_glyf_get_advance_with_var_unscaled (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical); namespace OT { @@ -62,7 +63,7 @@ struct LongMetric }; -template +template struct hmtxvmtx { bool sanitize (hb_sanitize_context_t *c HB_UNUSED) const @@ -73,11 +74,15 @@ struct hmtxvmtx return_trace (true); } + const hb_hashmap_t>* get_mtx_map (const hb_subset_plan_t *plan) const + { return T::is_horizontal ? &plan->hmtx_map : &plan->vmtx_map; } - bool subset_update_header (hb_subset_plan_t *plan, - unsigned int num_hmetrics) const + bool subset_update_header (hb_subset_context_t *c, + unsigned int num_hmetrics, + const hb_hashmap_t> *mtx_map, + const hb_map_t *bounds_map) const { - hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table (plan->source, H::tableTag); + hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table (c->plan->source, H::tableTag); hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob); hb_blob_destroy (src_blob); @@ -89,7 +94,56 @@ struct hmtxvmtx H *table = (H *) hb_blob_get_data (dest_blob, &length); table->numberOfLongMetrics = num_hmetrics; - bool result = plan->add_table (H::tableTag, dest_blob); +#ifndef HB_NO_VAR + if (c->plan->normalized_coords) + { + auto &MVAR = *c->plan->source->table.MVAR; + if (T::is_horizontal) + { + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE, caretSlopeRise); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN, caretSlopeRun); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET, caretOffset); + } + else + { + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RISE, caretSlopeRise); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_RUN, caretSlopeRun); + HB_ADD_MVAR_VAR (HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET, caretOffset); + } + + int min_lsb = 0x7FFF; + int min_rsb = 0x7FFF; + int max_extent = -0x7FFF; + unsigned max_adv = 0; + for (const auto _ : *mtx_map) + { + hb_codepoint_t gid = _.first; + unsigned adv = _.second.first; + int lsb = _.second.second; + max_adv = hb_max (max_adv, adv); + + if (bounds_map->has (gid)) + { + unsigned bound_width = bounds_map->get (gid); + int rsb = adv - lsb - bound_width; + int extent = lsb + bound_width; + min_lsb = hb_min (min_lsb, lsb); + min_rsb = hb_min (min_rsb, rsb); + max_extent = hb_max (max_extent, extent); + } + } + + table->advanceMax = max_adv; + if (!bounds_map->is_empty ()) + { + table->minLeadingBearing = min_lsb; + table->minTrailingBearing = min_rsb; + table->maxExtent = max_extent; + } + } +#endif + + bool result = c->plan->add_table (H::tableTag, dest_blob); hb_blob_destroy (dest_blob); return result; @@ -130,14 +184,15 @@ struct hmtxvmtx accelerator_t _mtx (c->plan->source); unsigned num_long_metrics; + const hb_hashmap_t> *mtx_map = get_mtx_map (c->plan); { /* Determine num_long_metrics to encode. */ auto& plan = c->plan; + num_long_metrics = plan->num_output_glyphs (); - hb_codepoint_t old_gid = 0; - unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0; + unsigned int last_advance = get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 1, _mtx); while (num_long_metrics > 1 && - last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0)) + last_advance == get_new_gid_advance_unscaled (plan, mtx_map, num_long_metrics - 2, _mtx)) { num_long_metrics--; } @@ -145,12 +200,18 @@ struct hmtxvmtx auto it = + hb_range (c->plan->num_output_glyphs ()) - | hb_map ([c, &_mtx] (unsigned _) + | hb_map ([c, &_mtx, mtx_map] (unsigned _) { - hb_codepoint_t old_gid; - if (!c->plan->old_gid_for_new_gid (_, &old_gid)) - return hb_pair (0u, 0); - return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid)); + if (!mtx_map->has (_)) + { + hb_codepoint_t old_gid; + if (!c->plan->old_gid_for_new_gid (_, &old_gid)) + return hb_pair (0u, 0); + int lsb = 0; + (void) _mtx.get_leading_bearing_without_var_unscaled (old_gid, &lsb); + return hb_pair (_mtx.get_advance_without_var_unscaled (old_gid), +lsb); + } + return mtx_map->get (_); }) ; @@ -160,7 +221,8 @@ struct hmtxvmtx return_trace (false); // Amend header num hmetrics - if (unlikely (!subset_update_header (c->plan, num_long_metrics))) + if (unlikely (!subset_update_header (c, num_long_metrics, mtx_map, + T::is_horizontal ? &c->plan->bounds_width_map : &c->plan->bounds_height_map))) return_trace (false); return_trace (true); @@ -173,7 +235,7 @@ struct hmtxvmtx accelerator_t (hb_face_t *face) { table = hb_sanitize_context_t ().reference_table (face, T::tableTag); - var_table = hb_sanitize_context_t ().reference_table (face, T::variationsTag); + var_table = hb_sanitize_context_t ().reference_table (face, T::variationsTag); default_advance = T::is_horizontal ? hb_face_get_upem (face) / 2 : hb_face_get_upem (face); @@ -221,36 +283,46 @@ struct hmtxvmtx bool has_data () const { return (bool) num_bearings; } - int get_side_bearing (hb_codepoint_t glyph) const + bool get_leading_bearing_without_var_unscaled (hb_codepoint_t glyph, + int *lsb) const { if (glyph < num_long_metrics) - return table->longMetricZ[glyph].sb; + { + *lsb = table->longMetricZ[glyph].sb; + return true; + } if (unlikely (glyph >= num_bearings)) - return 0; + return false; const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; - return bearings[glyph - num_long_metrics]; + *lsb = bearings[glyph - num_long_metrics]; + return true; } - int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const + bool get_leading_bearing_with_var_unscaled (hb_font_t *font, + hb_codepoint_t glyph, + int *lsb) const { - int side_bearing = get_side_bearing (glyph); + if (!font->num_coords) + return get_leading_bearing_without_var_unscaled (glyph, lsb); #ifndef HB_NO_VAR - if (unlikely (glyph >= num_bearings) || !font->num_coords) - return side_bearing; - - if (var_table.get_length ()) - return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); + float delta; + if (var_table->get_lsb_delta_unscaled (glyph, font->coords, font->num_coords, &delta) && + get_leading_bearing_without_var_unscaled (glyph, lsb)) + { + *lsb += roundf (delta); + return true; + } - return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); + return _glyf_get_leading_bearing_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx, lsb); #else - return side_bearing; + return false; #endif } - unsigned int get_advance (hb_codepoint_t glyph) const + unsigned int get_advance_without_var_unscaled (hb_codepoint_t glyph) const { /* OpenType case. */ if (glyph < num_bearings) @@ -262,7 +334,7 @@ struct hmtxvmtx if (unlikely (!num_advances)) return default_advance; -#ifdef HB_NO_BORING_EXPANSION +#ifdef HB_NO_BEYOND_64K return 0; #endif @@ -272,10 +344,8 @@ struct hmtxvmtx /* num_bearings <= glyph < num_glyphs; * num_bearings <= num_advances */ - /* TODO Optimize */ - if (num_bearings == num_advances) - return get_advance (num_bearings - 1); + return get_advance_without_var_unscaled (num_bearings - 1); const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics]; @@ -283,20 +353,22 @@ struct hmtxvmtx return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)]; } - unsigned int get_advance (hb_codepoint_t glyph, - hb_font_t *font, - VariationStore::cache_t *store_cache = nullptr) const + unsigned get_advance_with_var_unscaled (hb_codepoint_t glyph, + hb_font_t *font, + VariationStore::cache_t *store_cache = nullptr) const { - unsigned int advance = get_advance (glyph); + unsigned int advance = get_advance_without_var_unscaled (glyph); #ifndef HB_NO_VAR if (unlikely (glyph >= num_bearings) || !font->num_coords) return advance; if (var_table.get_length ()) - return advance + roundf (var_table->get_advance_var (glyph, font, store_cache)); // TODO Optimize?! + return advance + roundf (var_table->get_advance_delta_unscaled (glyph, + font->coords, font->num_coords, + store_cache)); - return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx); + return _glyf_get_advance_with_var_unscaled (font, glyph, T::tableTag == HB_OT_TAG_vmtx); #else return advance; #endif @@ -313,9 +385,25 @@ struct hmtxvmtx public: hb_blob_ptr_t table; - hb_blob_ptr_t var_table; + hb_blob_ptr_t var_table; }; + /* get advance: when no variations, call get_advance_without_var_unscaled. + * when there're variations, get advance value from mtx_map in subset_plan*/ + unsigned get_new_gid_advance_unscaled (const hb_subset_plan_t *plan, + const hb_hashmap_t> *mtx_map, + unsigned new_gid, + const accelerator_t &_mtx) const + { + if (mtx_map->is_empty ()) + { + hb_codepoint_t old_gid = 0; + return plan->old_gid_for_new_gid (new_gid, &old_gid) ? + _mtx.get_advance_without_var_unscaled (old_gid) : 0; + } + return mtx_map->get (new_gid).first; + } + protected: UnsizedArrayOf longMetricZ; /* Paired advance width and leading @@ -346,12 +434,12 @@ struct hmtxvmtx DEFINE_SIZE_ARRAY (0, longMetricZ); }; -struct hmtx : hmtxvmtx { +struct hmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR; static constexpr bool is_horizontal = true; }; -struct vmtx : hmtxvmtx { +struct vmtx : hmtxvmtx { static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx; static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR; static constexpr bool is_horizontal = false; diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh index b9b5b76a97c..bcf12221619 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-base-table.hh @@ -49,7 +49,7 @@ struct BaseCoordFormat1 bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - return_trace (likely (c->check_struct (this))); + return_trace (c->check_struct (this)); } protected: diff --git a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh index ed8acdbd62a..73cf84ed39d 100644 --- a/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh +++ b/src/java.desktop/share/native/libharfbuzz/hb-ot-layout-common.hh @@ -35,69 +35,42 @@ #include "hb-set.hh" #include "hb-bimap.hh" +#include "OT/Layout/Common/Coverage.hh" +#include "OT/Layout/types.hh" -#ifndef HB_MAX_NESTING_LEVEL -#define HB_MAX_NESTING_LEVEL 64 -#endif -#ifndef HB_MAX_CONTEXT_LENGTH -#define HB_MAX_CONTEXT_LENGTH 64 -#endif -#ifndef HB_CLOSURE_MAX_STAGES -/* - * The maximum number of times a lookup can be applied during shaping. - * Used to limit the number of iterations of the closure algorithm. - * This must be larger than the number of times add_pause() is - * called in a collect_features call of any shaper. - */ -#define HB_CLOSURE_MAX_STAGES 32 -#endif - -#ifndef HB_MAX_SCRIPTS -#define HB_MAX_SCRIPTS 500 -#endif - -#ifndef HB_MAX_LANGSYS -#define HB_MAX_LANGSYS 2000 -#endif - -#ifndef HB_MAX_LANGSYS_FEATURE_COUNT -#define HB_MAX_LANGSYS_FEATURE_COUNT 50000 -#endif - -#ifndef HB_MAX_FEATURES -#define HB_MAX_FEATURES 750 -#endif - -#ifndef HB_MAX_FEATURE_INDICES -#define HB_MAX_FEATURE_INDICES 1500 -#endif - -#ifndef HB_MAX_LOOKUP_VISIT_COUNT -#define HB_MAX_LOOKUP_VISIT_COUNT 35000 -#endif +// TODO(garretrieger): cleanup these after migration. +using OT::Layout::Common::Coverage; +using OT::Layout::Common::RangeRecord; +using OT::Layout::SmallTypes; +using OT::Layout::MediumTypes; namespace OT { - -#define NOT_COVERED ((unsigned int) -1) - - template -static inline void Coverage_serialize (hb_serialize_context_t *c, +static inline bool ClassDef_serialize (hb_serialize_context_t *c, Iterator it); -template -static inline void ClassDef_serialize (hb_serialize_context_t *c, - Iterator it); - -static void ClassDef_remap_and_serialize ( +static bool ClassDef_remap_and_serialize ( hb_serialize_context_t *c, const hb_set_t &klasses, bool use_class_zero, hb_sorted_vector_t> &glyph_and_klass, /* IN/OUT */ hb_map_t *klass_map /*IN/OUT*/); +struct hb_collect_feature_substitutes_with_var_context_t +{ + const hb_map_t *axes_index_tag_map; + const hb_hashmap_t *axes_location; + hb_hashmap_t> *record_cond_idx_map; + hb_hashmap_t *feature_substitutes_map; + + // not stored in subset_plan + hb_set_t *feature_indices; + bool apply; + unsigned cur_record_idx; + hb_hashmap_t, unsigned> *conditionset_map; +}; struct hb_prune_langsys_context_t { @@ -164,24 +137,40 @@ struct hb_subset_layout_context_t : const hb_map_t *lookup_index_map; const hb_hashmap_t> *script_langsys_map; const hb_map_t *feature_index_map; + const hb_hashmap_t *feature_substitutes_map; + hb_hashmap_t> *feature_record_cond_idx_map; + unsigned cur_script_index; + unsigned cur_feature_var_record_idx; hb_subset_layout_context_t (hb_subset_context_t *c_, - hb_tag_t tag_, - hb_map_t *lookup_map_, - hb_hashmap_t> *script_langsys_map_, - hb_map_t *feature_index_map_) : + hb_tag_t tag_) : subset_context (c_), table_tag (tag_), - lookup_index_map (lookup_map_), - script_langsys_map (script_langsys_map_), - feature_index_map (feature_index_map_), cur_script_index (0xFFFFu), + cur_feature_var_record_idx (0u), script_count (0), langsys_count (0), feature_index_count (0), lookup_index_count (0) - {} + { + if (tag_ == HB_OT_TAG_GSUB) + { + lookup_index_map = &c_->plan->gsub_lookups; + script_langsys_map = &c_->plan->gsub_langsys; + feature_index_map = &c_->plan->gsub_features; + feature_substitutes_map = &c_->plan->gsub_feature_substitutes_map; + feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gsub_feature_record_cond_idx_map; + } + else + { + lookup_index_map = &c_->plan->gpos_lookups; + script_langsys_map = &c_->plan->gpos_langsys; + feature_index_map = &c_->plan->gpos_features; + feature_substitutes_map = &c_->plan->gpos_feature_substitutes_map; + feature_record_cond_idx_map = c_->plan->user_axes_location.is_empty () ? nullptr : &c_->plan->gpos_feature_record_cond_idx_map; + } + } private: unsigned script_count; @@ -190,6 +179,7 @@ struct hb_subset_layout_context_t : unsigned lookup_index_count; }; +struct VariationStore; struct hb_collect_variation_indices_context_t : hb_dispatch_context_t { @@ -198,15 +188,27 @@ struct hb_collect_variation_indices_context_t : static return_t default_return_value () { return hb_empty_t (); } hb_set_t *layout_variation_indices; + hb_hashmap_t> *varidx_delta_map; + hb_font_t *font; + const VariationStore *var_store; const hb_set_t *glyph_set; const hb_map_t *gpos_lookups; + float *store_cache; hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_, + hb_hashmap_t> *varidx_delta_map_, + hb_font_t *font_, + const VariationStore *var_store_, const hb_set_t *glyph_set_, - const hb_map_t *gpos_lookups_) : + const hb_map_t *gpos_lookups_, + float *store_cache_) : layout_variation_indices (layout_variation_indices_), + varidx_delta_map (varidx_delta_map_), + font (font_), + var_store (var_store_), glyph_set (glyph_set_), - gpos_lookups (gpos_lookups_) {} + gpos_lookups (gpos_lookups_), + store_cache (store_cache_) {} }; template @@ -315,6 +317,31 @@ struct subset_record_array_t const void *base; }; +template +struct subset_record_array_arg_t +{ + subset_record_array_arg_t (hb_subset_layout_context_t *c_, OutputArray* out_, + const void *base_, + Arg &&arg_) : subset_layout_context (c_), + out (out_), base (base_), arg (arg_) {} + + template + void + operator () (T&& record) + { + auto snap = subset_layout_context->subset_context->serializer->snapshot (); + bool ret = record.subset (subset_layout_context, base, arg); + if (!ret) subset_layout_context->subset_context->serializer->revert (snap); + else out->len++; + } + + private: + hb_subset_layout_context_t *subset_layout_context; + OutputArray *out; + const void *base; + Arg &&arg; +}; + /* * Helper to subset a RecordList/record array. Subsets each Record in the array and * discards the record if the subset operation returns false. @@ -326,6 +353,13 @@ struct operator () (hb_subset_layout_context_t *c, OutputArray* out, const void *base) const { return subset_record_array_t (c, out, base); } + + /* Variant with one extra argument passed to subset */ + template + subset_record_array_arg_t + operator () (hb_subset_layout_context_t *c, OutputArray* out, + const void *base, Arg &&arg) const + { return subset_record_array_arg_t (c, out, base, arg); } } HB_FUNCOBJ (subset_record_array); @@ -377,166 +411,6 @@ HB_FUNCOBJ (serialize_math_record_array); * Script, ScriptList, LangSys, Feature, FeatureList, Lookup, LookupList */ -struct Record_sanitize_closure_t { - hb_tag_t tag; - const void *list_base; -}; - -template -struct Record -{ - int cmp (hb_tag_t a) const { return tag.cmp (a); } - - bool subset (hb_subset_layout_context_t *c, const void *base) const - { - TRACE_SUBSET (this); - auto *out = c->subset_context->serializer->embed (this); - if (unlikely (!out)) return_trace (false); - bool ret = out->offset.serialize_subset (c->subset_context, offset, base, c, &tag); - return_trace (ret); - } - - bool sanitize (hb_sanitize_context_t *c, const void *base) const - { - TRACE_SANITIZE (this); - const Record_sanitize_closure_t closure = {tag, base}; - return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure)); - } - - Tag tag; /* 4-byte Tag identifier */ - Offset16To - offset; /* Offset from beginning of object holding - * the Record */ - public: - DEFINE_SIZE_STATIC (6); -}; - -template -struct RecordArrayOf : SortedArray16Of> -{ - const Offset16To& get_offset (unsigned int i) const - { return (*this)[i].offset; } - Offset16To& get_offset (unsigned int i) - { return (*this)[i].offset; } - const Tag& get_tag (unsigned int i) const - { return (*this)[i].tag; } - unsigned int get_tags (unsigned int start_offset, - unsigned int *record_count /* IN/OUT */, - hb_tag_t *record_tags /* OUT */) const - { - if (record_count) - { - + this->sub_array (start_offset, record_count) - | hb_map (&Record::tag) - | hb_sink (hb_array (record_tags, *record_count)) - ; - } - return this->len; - } - bool find_index (hb_tag_t tag, unsigned int *index) const - { - return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX); - } -}; - -template -struct RecordListOf : RecordArrayOf -{ - const Type& operator [] (unsigned int i) const - { return this+this->get_offset (i); } - - bool subset (hb_subset_context_t *c, - hb_subset_layout_context_t *l) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (*this); - if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - - + this->iter () - | hb_apply (subset_record_array (l, out, this)) - ; - return_trace (true); - } - - bool sanitize (hb_sanitize_context_t *c) const - { - TRACE_SANITIZE (this); - return_trace (RecordArrayOf::sanitize (c, this)); - } -}; - -struct Feature; - -struct RecordListOfFeature : RecordListOf -{ - bool subset (hb_subset_context_t *c, - hb_subset_layout_context_t *l) const - { - TRACE_SUBSET (this); - auto *out = c->serializer->start_embed (*this); - if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false); - - unsigned count = this->len; - + hb_zip (*this, hb_range (count)) - | hb_filter (l->feature_index_map, hb_second) - | hb_map (hb_first) - | hb_apply (subset_record_array (l, out, this)) - ; - return_trace (true); - } -}; - -struct Script; -struct RecordListOfScript : RecordListOf