diff --git a/doc/building.html b/doc/building.html index 53defa0c61c8..fb18b1589c37 100644 --- a/doc/building.html +++ b/doc/building.html @@ -11,8 +11,11 @@ div.columns{display: flex; gap: min(4vw, 1.5em);} div.column{flex: auto; overflow-x: auto;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} - ul.task-list{list-style: none;} + /* The extra [class] is a hack that increases specificity enough to + override a similar rule in reveal.js */ + ul.task-list[class]{list-style: none;} ul.task-list li input[type="checkbox"] { + font-size: inherit; width: 0.8em; margin: 0 0.8em 0.2em -1.6em; vertical-align: middle; @@ -21,9 +24,6 @@ -
@@ -302,8 +302,8 @@

Special Considerations

in one of the columns of the ouput. If a directory is missing a short name, the safest way to get one is to enable short names for that particular volume with -fsutil 8dot3name set <drive letter>: 0 (note that -you need to run as administrator for this), and then re-create the +fsutil 8dot3name set <drive letter>: 0 (note that you +need to run as administrator for this), and then re-create the particular directory. A short name should be generated automatically then. Another option is to manually assign a short name to the directory using @@ -366,13 +366,14 @@

Building on aarch64

also possible to use cross-compiling.

Branch Protection

In order to use Branch Protection features in the VM, ---enable-branch-protection must be used. This option requires C++ -compiler support for -mbranch-protection=standard in GCC 9.1.0+ or -Clang 10+ on Linux/AArch64 or for /guard:signret in Visual Studio -2019+ on Windows/ARM64. The resulting build can be run on both machines with and -without support for branch protection in hardware. Branch Protection is fully -supported for the Linux/AArch64 target and only partially supported for the -Windows/ARM64 targets.

+--enable-branch-protection must be used. This option +requires C++ compiler support for +-mbranch-protection=standard in GCC 9.1.0+ or Clang 10+ on +Linux/AArch64 or for /guard:signret in Visual Studio 2019+ +on Windows/ARM64. The resulting build can be run on both machines with +and without support for branch protection in hardware. Branch Protection +is fully supported for the Linux/AArch64 target and only partially +supported for the Windows/ARM64 target.

Building on 32-bit ARM

This is not recommended. Instead, see the section on Cross-compiling.

@@ -389,25 +390,25 @@

Operating System to date at the time of writing.

- + - + - + - + - + @@ -580,25 +581,25 @@

Native Compiler system and toolchain.

Operating system Vendor/version used
Linux/x64 Oracle Linux 6.4 / 8.x
Linux/aarch64 Oracle Linux 7.6 / 8.x
macOS macOS 14.x
Windows Windows Server 2016
- + - + - + - + - + @@ -612,21 +613,21 @@

Native Compiler to compile successfully without issues.

Operating system Supported toolchain
Linux gcc, clang
macOS Apple Xcode (using clang)
AIX IBM Open XL C/C++
Windows Microsoft Visual Studio
- + - + - + - + @@ -902,7 +903,7 @@

Graphviz and Pandoc

href="https://pandoc.org">Pandoc is required. For full docs also Graphviz is required. Any recent versions should work. For reference, and subject to change, Oracle -builds use Graphviz 9.0.0 and Pandoc 2.19.2.

+builds use Graphviz 9.0.0 and Pandoc 3.6.4.

Running Configure

To build the JDK, you need a "configuration", which consists of a directory where to store the build output, coupled with information @@ -1473,27 +1474,27 @@

Using OpenJDK Devkits

following targets are known to work:

Operating system Toolchain version
Linux gcc 14.2.0
macOS Apple Xcode 15.4 (using clang 15.0.0)
Windows Microsoft Visual Studio 2022 version 17.13.2
- + - + - + - + - + - + - + @@ -1589,7 +1590,7 @@

Using Debian debootstrap

- + @@ -1598,98 +1599,98 @@

Using Debian debootstrap

- + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1818,13 +1819,13 @@

Ccache

recommend evaluating it for yourself. To enable it, make sure it's on the path and configure with --enable-ccache.

Sccache

-

The JDK build supports building with sccache when using gcc, clang, or -Microsoft toolchains. To enable it, make sure the sccache binary is on the path -(or specify the path to the binary using the SCCACHE argument to -the configure script) and configure with --enable-sccache. To -optionally specify where sccache stores its cache files, use ---with-sccache-dir. Precompiled headers are disabled when sccache -is enabled.

+

The JDK build supports building with sccache when using gcc, clang, +or Microsoft toolchains. To enable it, make sure the sccache binary is +on the path (or specify the path to the binary using the +SCCACHE argument to the configure script) and configure +with --enable-sccache. To optionally specify where sccache +stores its cache files, use --with-sccache-dir. Precompiled +headers are disabled when sccache is enabled.

Precompiled Headers

By default, the Hotspot build uses pre-compiled headers (PCH) on the toolchains were it is properly supported (clang, gcc, and Visual @@ -1961,7 +1962,7 @@

Running "make doctor"

* Checking for warnings from configure... --- The following warnings were produced. Repeated here for convenience: -WARNING: pandoc is version 3.1.9, not the recommended version 2.19.2 +WARNING: pandoc is version 3.1.9, not the recommended version 3.6.4 --- ! Inspect the warnings, fix any problems, and re-run configure diff --git a/doc/building.md b/doc/building.md index 17eaf760b064..d273010ddc11 100644 --- a/doc/building.md +++ b/doc/building.md @@ -713,7 +713,7 @@ In order to build man pages and the full docs (see the `--enable-full-docs` configure option) [Pandoc](https://pandoc.org) is required. For full docs also [Graphviz](https://www.graphviz.org) is required. Any recent versions should work. For reference, and subject to change, Oracle builds use Graphviz -9.0.0 and Pandoc 2.19.2. +9.0.0 and Pandoc 3.6.4. ## Running Configure @@ -1720,7 +1720,7 @@ certain well-known problems, but it can never find all possible errors. * Checking for warnings from configure... --- The following warnings were produced. Repeated here for convenience: -WARNING: pandoc is version 3.1.9, not the recommended version 2.19.2 +WARNING: pandoc is version 3.1.9, not the recommended version 3.6.4 --- ! Inspect the warnings, fix any problems, and re-run configure diff --git a/doc/hotspot-style.html b/doc/hotspot-style.html index c7126622c7d2..f0e07630a21a 100644 --- a/doc/hotspot-style.html +++ b/doc/hotspot-style.html @@ -11,8 +11,11 @@ div.columns{display: flex; gap: min(4vw, 1.5em);} div.column{flex: auto; overflow-x: auto;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} - ul.task-list{list-style: none;} + /* The extra [class] is a hack that increases specificity enough to + override a similar rule in reveal.js */ + ul.task-list[class]{list-style: none;} ul.task-list li input[type="checkbox"] { + font-size: inherit; width: 0.8em; margin: 0 0.8em 0.2em -1.6em; vertical-align: middle; @@ -20,9 +23,6 @@ .display.math{display: block; text-align: center; margin: 0.5rem auto;} -
diff --git a/doc/hotspot-unit-tests.html b/doc/hotspot-unit-tests.html index 5cc424322f9c..a4a01b470515 100644 --- a/doc/hotspot-unit-tests.html +++ b/doc/hotspot-unit-tests.html @@ -11,8 +11,11 @@ div.columns{display: flex; gap: min(4vw, 1.5em);} div.column{flex: auto; overflow-x: auto;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} - ul.task-list{list-style: none;} + /* The extra [class] is a hack that increases specificity enough to + override a similar rule in reveal.js */ + ul.task-list[class]{list-style: none;} ul.task-list li input[type="checkbox"] { + font-size: inherit; width: 0.8em; margin: 0 0.8em 0.2em -1.6em; vertical-align: middle; @@ -20,9 +23,6 @@ .display.math{display: block; text-align: center; margin: 0.5rem auto;} -
diff --git a/doc/ide.html b/doc/ide.html index ef6f434013ed..2407becf94df 100644 --- a/doc/ide.html +++ b/doc/ide.html @@ -11,8 +11,11 @@ div.columns{display: flex; gap: min(4vw, 1.5em);} div.column{flex: auto; overflow-x: auto;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} - ul.task-list{list-style: none;} + /* The extra [class] is a hack that increases specificity enough to + override a similar rule in reveal.js */ + ul.task-list[class]{list-style: none;} ul.task-list li input[type="checkbox"] { + font-size: inherit; width: 0.8em; margin: 0 0.8em 0.2em -1.6em; vertical-align: middle; @@ -20,9 +23,6 @@ .display.math{display: block; text-align: center; margin: 0.5rem auto;} -
diff --git a/doc/starting-next-release.html b/doc/starting-next-release.html index bbb48e243ad5..a03044097e7c 100644 --- a/doc/starting-next-release.html +++ b/doc/starting-next-release.html @@ -11,8 +11,11 @@ div.columns{display: flex; gap: min(4vw, 1.5em);} div.column{flex: auto; overflow-x: auto;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} - ul.task-list{list-style: none;} + /* The extra [class] is a hack that increases specificity enough to + override a similar rule in reveal.js */ + ul.task-list[class]{list-style: none;} ul.task-list li input[type="checkbox"] { + font-size: inherit; width: 0.8em; margin: 0 0.8em 0.2em -1.6em; vertical-align: middle; @@ -20,9 +23,6 @@ .display.math{display: block; text-align: center; margin: 0.5rem auto;} -
diff --git a/doc/testing.html b/doc/testing.html index f52f72ac2f7d..bb6af964c295 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -11,8 +11,11 @@ div.columns{display: flex; gap: min(4vw, 1.5em);} div.column{flex: auto; overflow-x: auto;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} - ul.task-list{list-style: none;} + /* The extra [class] is a hack that increases specificity enough to + override a similar rule in reveal.js */ + ul.task-list[class]{list-style: none;} ul.task-list li input[type="checkbox"] { + font-size: inherit; width: 0.8em; margin: 0 0.8em 0.2em -1.6em; vertical-align: middle; @@ -21,9 +24,6 @@ -
@@ -494,8 +494,8 @@

VALUE_CLASS_PLUGIN

In the meantime, this mode allows test sources to compile and run as either value classes or regular identity classes without source-level changes.

-

When set to any non-empty value, the following options are appended to -every JTReg invocation:

+

When set to any non-empty value, the following options are appended +to every JTReg invocation:

  • -cpa:<valueClassPlugin.jar> — appends the plugin JAR to the compile-time classpath (only when the JAR is present in the @@ -511,16 +511,15 @@

    VALUE_CLASS_PLUGIN

    plugin.

The plugin scans each compilation unit after parsing and converts any -class annotated with -@jdk.test.lib.valueclass.AsValueClass into a value class by -setting the internal VALUE_CLASS modifier flag and clearing -the IDENTITY_TYPE flag. This transformation only takes -effect when --enable-preview is active; without it the -annotation is a no-op and the class compiles as an ordinary identity -class, so the same test source can exercise both code paths.

+class annotated with @jdk.test.lib.valueclass.AsValueClass +into a value class by setting the internal VALUE_CLASS +modifier flag and clearing the IDENTITY_TYPE flag. This +transformation only takes effect when --enable-preview is +active; without it the annotation is a no-op and the class compiles as +an ordinary identity class, so the same test source can exercise both +code paths.

Example:

-
$ make test TEST=jdk_lang JTREG="VALUE_CLASS_PLUGIN=true"
-
+
$ make test TEST=jdk_lang JTREG="VALUE_CLASS_PLUGIN=true"

JVMTI_STRESS_AGENT

Executes JTReg tests with JVM TI stress agent. The stress agent is the part of test library and located in diff --git a/doc/value-class-preview.html b/doc/value-class-preview.html index 04b8ffb0f9bf..b6c84f2386d6 100644 --- a/doc/value-class-preview.html +++ b/doc/value-class-preview.html @@ -11,8 +11,11 @@ div.columns{display: flex; gap: min(4vw, 1.5em);} div.column{flex: auto; overflow-x: auto;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} - ul.task-list{list-style: none;} + /* The extra [class] is a hack that increases specificity enough to + override a similar rule in reveal.js */ + ul.task-list[class]{list-style: none;} ul.task-list li input[type="checkbox"] { + font-size: inherit; width: 0.8em; margin: 0 0.8em 0.2em -1.6em; vertical-align: middle; @@ -21,9 +24,6 @@ -

diff --git a/make/Docs.gmk b/make/Docs.gmk index a4a4bc60363e..e4697202712b 100644 --- a/make/Docs.gmk +++ b/make/Docs.gmk @@ -705,12 +705,13 @@ endif SPEC_HEADER_BLOCK := \
\ - \
JDWP_PROTOCOL := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/jdwp-protocol.html @@ -720,7 +721,8 @@ ifneq ($(call ApplySpecFilter, $(JDWP_PROTOCOL)), ) SOURCE_FILES := $(JDWP_PROTOCOL), \ OUTPUT_DIR := $(DOCS_OUTPUTDIR)/specs/jdwp, \ REPLACEMENTS := \ - @@ -196,22 +209,30 @@
-
+
-
-

+ +

-

+

+
+
-

+

+
+
-

+

+
+
-

+

+
+
-

-

-
+
+
+

Constant Index

@@ -220,17 +241,20 @@ +
-

-


-

- -

- +
+

+ +

+ +
-

+


+
+
@@ -248,8 +272,6 @@ -
-

@@ -287,89 +309,88 @@ -

+


+
-

-
-

- functions: -
    - -
- - - function types: -
    - -
-
- - - types: +

+ functions: -
- - - flags and constants: - + + + + flags and constants: + + + + +
-
+
+
- - - -
- - -
-      jvmtiError
+    
+    
+ + +
+        jvmtiError
 
-      (jvmtiEnv* env)
-
- - - - - - + (jvmtiEnv* env)
+
+ + + + + + +
@@ -420,7 +441,7 @@
- SetEventNotificationMode(JVMTI_ENABLE, + SetEventNotificationMode(JVMTI_ENABLE, , NULL)
@@ -523,35 +544,36 @@ -
+
+
- - -
-
-
-      typedef 
-      
-       (JNICALL *
-      
-      )
+    
+    
+
+
+        typedef 
+        
+         (JNICALL *
+        
+        )
     (
-      
-        
-        
+        
+          
+          
           ,
      
-          
+            
+          
         
-      
-      );
-    
-
- - -
+ ); +
+
+ + +
+
@@ -559,8 +581,6 @@ -
-

@@ -580,7 +600,6 @@ typedef struct { -

Event Index

Supported devkit targets
x86_64-linux-gnu
aarch64-linux-gnu
arm-linux-gnueabihf
ppc64le-linux-gnu
riscv64-linux-gnu
s390x-linux-gnu
Target Debian tree Debian arch
x86 buster i386 i386-linux-gnu (all)
arm buster armhf arm-linux-gnueabihf (all)
aarch64 buster arm64 aarch64-linux-gnu (all)
ppc64le buster ppc64el powerpc64le-linux-gnu (all)
s390x buster s390x s390x-linux-gnu (all)
mipsle buster mipsel mipsel-linux-gnu zero
mips64le buster mips64el mips64el-linux-gnueabi64 zero
armel buster arm arm-linux-gnueabi zero
ppc sid powerpc powerpc-linux-gnu zero
ppc64be sid ppc64 powerpc64-linux-gnu (all)
m68k sid m68k m68k-linux-gnu zero
alpha sid alpha alpha-linux-gnu zero
sh4 sid sh4 sh4-linux-gnu zero
riscv64 sid riscv64
Capabilities
@@ -1227,7 +1242,6 @@ typedef struct { -
@@ -1621,28 +1635,19 @@ typedef struct { -
-

Errors

-
-
-
-
-

Data Types

-
-
@@ -1653,7 +1658,6 @@ typedef struct {
Structure Type Definitions
-
@@ -1664,7 +1668,6 @@ typedef struct {
Function Type Definitions
-
@@ -1675,7 +1678,6 @@ typedef struct {
Enumeration Definitions
-
@@ -1688,7 +1690,6 @@ typedef struct {
Function Table Layout
-
@@ -1762,11 +1763,9 @@ typedef struct { -
-
@@ -1780,7 +1779,6 @@ typedef struct {
-
@@ -1793,14 +1791,10 @@ typedef struct { -
-

Change History

Last update:
Version: -
-
@@ -1865,7 +1859,7 @@ typedef struct { -

+

Rationale:

@@ -1873,7 +1867,7 @@ typedef struct { -

+

To do:

@@ -1891,7 +1885,6 @@ typedef struct {
- @@ -1960,14 +1953,13 @@ typedef struct { + -
+ -
- -
+
@@ -2024,5 +2016,4 @@ typedef struct { JVM TI - diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index fbf959b4c635..03d6c15cfbd1 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -44,7 +44,6 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" -#include "oops/oopCast.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "oops/valueKlass.inline.hpp" #include "oops/valuePayload.inline.hpp" @@ -1276,78 +1275,74 @@ void IterateThroughHeapObjectClosure::do_object(oop obj) { } void IterateThroughHeapObjectClosure::visit_object(const JvmtiHeapwalkObject& obj) { - // apply class filter - if (is_filtered_by_klass_filter(obj, klass())) return; - - // prepare for callback - CallbackWrapper wrapper(tag_map(), obj); - - // check if filtered by the heap filter - if (is_filtered_by_heap_filter(wrapper.obj_tag(), wrapper.klass_tag(), heap_filter())) { - return; - } - - // for arrays we need the length, otherwise -1 bool is_array = obj.klass()->is_array_klass(); - int len = is_array ? arrayOop(obj.obj())->length() : -1; - - // invoke the object callback (if callback is provided) - if (callbacks()->heap_iteration_callback != nullptr) { - jvmtiHeapIterationCallback cb = callbacks()->heap_iteration_callback; - jint res = (*cb)(wrapper.klass_tag(), - wrapper.obj_size(), - wrapper.obj_tag_p(), - (jint)len, - (void*)user_data()); - if (check_flags_for_abort(res)) return; - } - - // for objects and classes we report primitive fields if callback provided - if (callbacks()->primitive_field_callback != nullptr && obj.klass()->is_instance_klass()) { - jint res; - jvmtiPrimitiveFieldCallback cb = callbacks()->primitive_field_callback; - if (obj.klass() == vmClasses::Class_klass()) { - assert(!obj.is_flat(), "Class object cannot be flattened"); - res = invoke_primitive_field_callback_for_static_fields(&wrapper, - obj.obj(), - cb, - (void*)user_data()); - } else { - res = invoke_primitive_field_callback_for_instance_fields(&wrapper, - obj, - cb, - (void*)user_data()); - } - if (check_flags_for_abort(res)) return; - } - // string callback - if (!is_array && - callbacks()->string_primitive_value_callback != nullptr && - obj.klass() == vmClasses::String_klass()) { - jint res = invoke_string_value_callback( - callbacks()->string_primitive_value_callback, - &wrapper, - obj, - (void*)user_data()); - if (check_flags_for_abort(res)) return; - } + if (!is_filtered_by_klass_filter(obj, klass())) { // apply class filter + // prepare for callback + CallbackWrapper wrapper(tag_map(), obj); + + // check if filtered by the heap filter + if (!is_filtered_by_heap_filter(wrapper.obj_tag(), wrapper.klass_tag(), heap_filter())) { + // for arrays we need the length, otherwise -1 + int len = is_array ? arrayOop(obj.obj())->length() : -1; + + // invoke the object callback (if callback is provided) + if (callbacks()->heap_iteration_callback != nullptr) { + jvmtiHeapIterationCallback cb = callbacks()->heap_iteration_callback; + jint res = (*cb)(wrapper.klass_tag(), + wrapper.obj_size(), + wrapper.obj_tag_p(), + (jint)len, + (void*)user_data()); + if (check_flags_for_abort(res)) return; + } - // array callback - if (is_array && - callbacks()->array_primitive_value_callback != nullptr && - obj.klass()->is_typeArray_klass()) { - jint res = invoke_array_primitive_value_callback( - callbacks()->array_primitive_value_callback, - &wrapper, - obj, - (void*)user_data()); - if (check_flags_for_abort(res)) return; - } + // for objects and classes we report primitive fields if callback provided + if (callbacks()->primitive_field_callback != nullptr && obj.klass()->is_instance_klass()) { + jint res; + jvmtiPrimitiveFieldCallback cb = callbacks()->primitive_field_callback; + if (obj.klass() == vmClasses::Class_klass()) { + assert(!obj.is_flat(), "Class object cannot be flattened"); + res = invoke_primitive_field_callback_for_static_fields(&wrapper, + obj.obj(), + cb, + (void*)user_data()); + } else { + res = invoke_primitive_field_callback_for_instance_fields(&wrapper, + obj, + cb, + (void*)user_data()); + } + if (check_flags_for_abort(res)) return; + } - // All info for the object is reported. + // string callback + if (!is_array && + callbacks()->string_primitive_value_callback != nullptr && + obj.klass() == vmClasses::String_klass()) { + jint res = invoke_string_value_callback( + callbacks()->string_primitive_value_callback, + &wrapper, + obj, + (void*)user_data()); + if (check_flags_for_abort(res)) return; + } - // If the object has flat fields, report them as heap objects. + // array callback + if (is_array && + callbacks()->array_primitive_value_callback != nullptr && + obj.klass()->is_typeArray_klass()) { + jint res = invoke_array_primitive_value_callback( + callbacks()->array_primitive_value_callback, + &wrapper, + obj, + (void*)user_data()); + if (check_flags_for_abort(res)) return; + } + } + } + // If the object has flattened fields, report them as heap objects + // even though this object was not reported. if (obj.klass()->is_instance_klass()) { if (InstanceKlass::cast(obj.klass())->has_flat_fields()) { visit_flat_fields(obj); diff --git a/src/hotspot/share/prims/nativeEntryPoint.cpp b/src/hotspot/share/prims/nativeEntryPoint.cpp index 96f63d758875..2160d4859c1e 100644 --- a/src/hotspot/share/prims/nativeEntryPoint.cpp +++ b/src/hotspot/share/prims/nativeEntryPoint.cpp @@ -27,7 +27,7 @@ #include "code/vmreg.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" -#include "oops/oopCast.inline.hpp" +#include "oops/oop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/downcallLinker.hpp" #include "prims/foreignGlobals.inline.hpp" diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 4a0570f8d9e1..0243e64887d9 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -44,7 +44,6 @@ #include "oops/klass.inline.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" -#include "oops/oopCast.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "oops/valueKlass.inline.hpp" #include "oops/valuePayload.hpp" diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 00d2bc57ff1f..18b6d00a0896 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -596,7 +596,7 @@ WB_END WB_ENTRY(jboolean, WB_G1HasRegionsToUncommit(JNIEnv* env, jobject o)) if (UseG1GC) { - return G1CollectedHeap::heap()->has_uncommittable_regions(); + return G1CollectedHeap::heap()->has_pending_uncommit_regions(); } THROW_MSG_0(vmSymbols::java_lang_UnsupportedOperationException(), "WB_G1HasRegionsToUncommit: G1 GC is not enabled"); WB_END @@ -1143,7 +1143,7 @@ bool WhiteBox::compile_method(Method* method, int comp_level, int bci, JavaThrea bool is_blocking = !matcher.directive_set()->BackgroundCompilationOption; // Compile method and check result - nmethod* nm = CompileBroker::compile_method(mh, bci, comp_level, mh->invocation_count(), CompileTask::Reason_Whitebox, CHECK_false); + nmethod* nm = CompileBroker::compile_method(mh, bci, comp_level, mh->invocation_count(), nullptr, CompileTask::Reason_Whitebox, CHECK_false); MutexLocker mu(THREAD, Compile_lock); bool is_queued = mh->queued_for_compilation(); if ((!is_blocking && is_queued) || nm != nullptr) { diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index b661acf488c7..348727c439eb 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -26,6 +26,7 @@ #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/vmClasses.hpp" +#include "code/aotCodeCache.hpp" #include "code/codeCache.hpp" #include "code/debugInfoRec.hpp" #include "code/nmethod.hpp" @@ -1829,8 +1830,11 @@ static void log_uncommon_trap(nmethod* nm, Method* tm, intptr_t pc, frame& fr, i if (class_name != nullptr) { ls.print("%s class_name=%s ", unresolved ? "unresolved" : "", class_name); } - ls.print("cid=%4d %s level=%d ", - nm->compile_id(), (is_osr ? "osr" : ""), nm->comp_level()); + ls.print("cid=%4d %s%s%s level=%d ", + nm->compile_id(), (is_osr ? "osr" : " "), + (nm->is_aot() ? "aot " : ""), + (nm->aot_preloaded() ? "preload " : ""), + nm->comp_level()); ls.print_cr("pc=" INTPTR_FORMAT " relative_pc=" INTPTR_FORMAT, pc, fr.pc() - nm->code_begin()); @@ -1881,7 +1885,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr gather_statistics(reason, action, trap_bc); // Ensure that we can record deopt. history: - bool create_if_missing = ProfileTraps; + bool create_if_missing = ProfileTraps || AOTCodeCache::is_using_code(); methodHandle profiled_method; profiled_method = trap_method; diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp index 24d55c2d52d9..d30734ac4c12 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.cpp @@ -453,3 +453,24 @@ JVMFlag::Error ControlIntrinsicConstraintFunc(ccstrlist value, bool verbose) { return JVMFlag::SUCCESS; } +JVMFlag::Error DisableAOTCodeConstraintFunc(uint value, bool verbose) { + const int max_modes = 5; + uint original_value = value; + for (int i = 0; i < max_modes; i++) { + if (value % 10 > 1) { + JVMFlag::printError(verbose, + "Invalid value (" UINT32_FORMAT ") " + "in DisableAOTCode at position %d\n", value, i); + return JVMFlag::VIOLATES_CONSTRAINT; + } + value = value / 10; + } + if (value != 0) { + JVMFlag::printError(verbose, + "Invalid value (" UINT32_FORMAT ") " + "for DisableAOTCode: maximal %d digits\n", original_value, max_modes); + return JVMFlag::VIOLATES_CONSTRAINT; + } + return JVMFlag::SUCCESS; +} + diff --git a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp index 45e91058e0b5..3eaa31f20e62 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp +++ b/src/hotspot/share/runtime/flags/jvmFlagConstraintsCompiler.hpp @@ -52,6 +52,7 @@ f(intx, InitArrayShortSizeConstraintFunc) \ f(ccstrlist, DisableIntrinsicConstraintFunc) \ f(ccstrlist, ControlIntrinsicConstraintFunc) \ + f(uint, DisableAOTCodeConstraintFunc) \ COMPILER2_PRESENT( \ f(intx, InteriorEntryAlignmentConstraintFunc) \ f(intx, NodeLimitFudgeFactorConstraintFunc) \ diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 2d1191e8eb00..d5fbd76666e1 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -689,6 +689,8 @@ void frame::print_C_frame(outputStream* st, char* buf, int buflen, address pc) { // First letter indicates type of the frame: // J: Java frame (compiled) // j: Java frame (interpreted) +// A: Java frame (AOT compiled and loaded after class initialization) +// P: Java frame (AOT compiled and preloaded before class initialization) // V: VM frame (C/C++) // v: Other frames running VM generated code (e.g. stubs, adapters, etc.) // C: C/C++ frame @@ -729,7 +731,8 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose nmethod* nm = _cb->as_nmethod(); Method* m = nm->method(); if (m != nullptr) { - st->print("J %d%s", nm->compile_id(), (nm->is_osr_method() ? "%" : "")); + st->print("%s", (nm->aot_preloaded() ? "P" : (nm->is_aot() ? "A" : "J"))); + st->print(" %d%s", nm->compile_id(), (nm->is_osr_method() ? "%" : "")); st->print(" %s", nm->compiler_name()); m->name_and_sig_as_C_string(buf, buflen); st->print(" %s", buf); diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 335f2ea19251..37f4e3f9e4af 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -126,7 +126,11 @@ const size_t minimumSymbolTableSize = 1024; \ product(bool, AOTCompatibleOopCompression, false, DIAGNOSTIC, \ "Always use HeapBasedNarrowOop mode, so that AOT code will " \ - "always work regardless of runtime heap range") \ + "always work regardless of runtime heap range; this is set " \ + "by default when assembling an AOT cache which contains code, " \ + "and by default in a production run that uses that AOT cache; " \ + "to diagnose possible effects on performance, you can assemble " \ + "an AOT cache by disabling either AOTCodeCaching or this flag") \ \ product(bool, UseCompactObjectHeaders, true, \ "Use compact 64-bit object headers in 64-bit VM") \ @@ -1182,7 +1186,8 @@ const int ObjectAlignmentInBytes = 8; "Use population count instruction") \ \ develop(bool, TraceMethodReplacement, false, \ - "Print when methods are replaced do to recompilation") \ + "Print when AOT or tiered JIT methods are replaced due to " \ + "recompilation") \ \ product(intx, MinPassesBeforeFlush, 10, DIAGNOSTIC, \ "Minimum number of sweeper passes before an nmethod " \ diff --git a/src/hotspot/share/runtime/hotCodeCollector.cpp b/src/hotspot/share/runtime/hotCodeCollector.cpp index bb848582c46d..819894a08740 100644 --- a/src/hotspot/share/runtime/hotCodeCollector.cpp +++ b/src/hotspot/share/runtime/hotCodeCollector.cpp @@ -112,6 +112,14 @@ void HotCodeCollector::thread_entry(JavaThread* thread, TRAPS) { } } +static nmethod* find_nmethod(void* addr) { + if (addr == nullptr) { + return nullptr; + } + CodeBlob* blob = CodeCache::find_blob(addr); + return blob == nullptr ? nullptr : blob->as_nmethod_or_null(); +} + void HotCodeCollector::do_grouping(Candidates& candidates) { // Number of nmethods relocated (candidate + callees) int num_relocated = 0; @@ -131,14 +139,25 @@ void HotCodeCollector::do_grouping(Candidates& candidates) { break; } - nmethod* candidate = candidates.get_candidate(); + Candidate candidate = candidates.get_candidate(); MutexLocker ml_Compile_lock(Compile_lock); MutexLocker ml_CompiledIC_lock(CompiledIC_lock, Mutex::_no_safepoint_check_flag); MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag); - switch (do_relocation(candidate, 0, &num_relocated)) { + nmethod* nm = find_nmethod(candidate.get_nmethod()); + if (nm == nullptr || + nm != candidate.get_nmethod() || + nm->compile_id() != candidate.get_compile_id()) { + log_debug(hotcode)("Skipped stale candidate: address=%p, compile_id=%d, samples=%d", + candidate.get_nmethod(), candidate.get_compile_id(), candidate.get_sample_count()); + num_skipped++; + continue; + } + + switch (do_relocation(nm, 0, &num_relocated)) { case nmethod::RelocationResult::SUCCESS: + candidates.move_samples_to_hot(candidate.get_sample_count()); break; case nmethod::RelocationResult::FAILED_NO_SPACE_IN_CODE_HEAP: { CodeHeap* heap = CodeCache::get_code_heap(CodeBlobType::MethodHot); @@ -153,6 +172,9 @@ void HotCodeCollector::do_grouping(Candidates& candidates) { break; } case nmethod::RelocationResult::FAILED_NOT_RELOCATABLE_NMETHOD: + if (nm->method() != nullptr) { + log_debug(hotcode)("Skipped not relocatable nmethod: %s", nm->method()->name_and_sig_as_C_string()); + } num_skipped++; break; case nmethod::RelocationResult::FAILED_INVALIDATED_NMETHOD: @@ -165,21 +187,9 @@ void HotCodeCollector::do_grouping(Candidates& candidates) { "Skipped %d candidates. %d candidates invalidated during relocation.", num_relocated, num_skipped, num_invalidated); } -nmethod::RelocationResult HotCodeCollector::do_relocation(void* candidate, uint call_level, int* num_relocated) { +nmethod::RelocationResult HotCodeCollector::do_relocation(nmethod* nm, uint call_level, int* num_relocated) { assert(num_relocated != nullptr, "num_relocated must be provided"); - if (candidate == nullptr) { - return nmethod::RelocationResult::FAILED_NOT_RELOCATABLE_NMETHOD; - } - - // Verify that address still points to CodeBlob - CodeBlob* blob = CodeCache::find_blob(candidate); - if (blob == nullptr) { - return nmethod::RelocationResult::FAILED_NOT_RELOCATABLE_NMETHOD; - } - - // Verify that blob is nmethod - nmethod* nm = blob->as_nmethod_or_null(); if (nm == nullptr || nm->method() == nullptr) { return nmethod::RelocationResult::FAILED_NOT_RELOCATABLE_NMETHOD; } @@ -235,7 +245,7 @@ nmethod::RelocationResult HotCodeCollector::do_relocation(void* candidate, uint address dest = ((CallRelocation*) reloc)->destination(); // Recursively relocate callees - if (do_relocation(dest, call_level + 1, num_relocated) == nmethod::RelocationResult::FAILED_NO_SPACE_IN_CODE_HEAP) { + if (do_relocation(find_nmethod(dest), call_level + 1, num_relocated) == nmethod::RelocationResult::FAILED_NO_SPACE_IN_CODE_HEAP) { return nmethod::RelocationResult::FAILED_NO_SPACE_IN_CODE_HEAP; } } diff --git a/src/hotspot/share/runtime/hotCodeCollector.hpp b/src/hotspot/share/runtime/hotCodeCollector.hpp index 0c4e853730e0..d6efee3360ae 100644 --- a/src/hotspot/share/runtime/hotCodeCollector.hpp +++ b/src/hotspot/share/runtime/hotCodeCollector.hpp @@ -42,7 +42,7 @@ class HotCodeCollector : public JavaThread { static void do_grouping(Candidates& candidates); - static nmethod::RelocationResult do_relocation(void* candidate, uint call_level, int* num_relocated); + static nmethod::RelocationResult do_relocation(nmethod* candidate, uint call_level, int* num_relocated); public: static void initialize(); diff --git a/src/hotspot/share/runtime/hotCodeSampler.cpp b/src/hotspot/share/runtime/hotCodeSampler.cpp index e033765c1f20..33579d1b2685 100644 --- a/src/hotspot/share/runtime/hotCodeSampler.cpp +++ b/src/hotspot/share/runtime/hotCodeSampler.cpp @@ -25,6 +25,7 @@ #ifdef COMPILER2 #include "code/codeCache.hpp" +#include "code/nmethod.hpp" #include "logging/log.hpp" #include "runtime/hotCodeSampler.hpp" #include "runtime/javaThread.inline.hpp" @@ -62,50 +63,63 @@ bool ThreadSampler::sample_all_java_threads() { } CodeBlob* cb = CodeCache::find_blob(pc); - if (cb != nullptr && cb->is_nmethod()) { - bool created = false; - int *count = _samples.put_if_absent(cb->as_nmethod(), 0, &created); - (*count)++; - if (created) { - _samples.maybe_grow(); - } + if (cb == nullptr || !cb->is_nmethod()) { + continue; + } + + nmethod* nm = cb->as_nmethod(); + + // We can dereference the nmethod pointer here because we are sampling from a JavaThread and + // the code blob cannot be purged while the thread does not reach a safepoint. + assert(Thread::current()->is_Java_thread(), "ThreadSampler should only be called from a JavaThread"); + int compile_id = nm->compile_id(); + CodeBlobType code_blob_type = CodeCache::get_code_blob_type(nm); + + if (code_blob_type == CodeBlobType::MethodHot) { + _hot_sample_count++; + continue; + } + + if (code_blob_type != CodeBlobType::MethodNonProfiled) { + continue; + } + + _non_profiled_sample_count++; + + bool created = false; + Pair* sampled_nm = _samples.put_if_absent(compile_id, Pair(nm, 0), &created); + sampled_nm->second++; + if (created) { + _samples.maybe_grow(); } } return true; } +#define NMETHOD_PTR(sampled_nm) (sampled_nm.first) +#define SAMPLE_COUNT(sampled_nm) (sampled_nm.second) + Candidates::Candidates(ThreadSampler& sampler) - : _hot_sample_count(0), _non_profiled_sample_count(0) { - auto func = [&](nmethod* nm, int count) { - if (CodeCache::get_code_blob_type(nm) == CodeBlobType::MethodNonProfiled) { - _candidates.append(Pair(nm, count)); - add_non_profiled_sample_count(count); - } else if (CodeCache::get_code_blob_type(nm) == CodeBlobType::MethodHot) { - add_hot_sample_count(count); - } + : _hot_sample_count(sampler.hot_sample_count()), + _non_profiled_sample_count(sampler.non_profiled_sample_count()) { + auto func = [&](int compile_id, const Pair sampled_nm) { + _candidates.append(Candidate(NMETHOD_PTR(sampled_nm), compile_id, SAMPLE_COUNT(sampled_nm))); }; sampler.iterate_samples(func); log_info(hotcode)("Generated candidate list from %d samples corresponding to %d nmethods", _non_profiled_sample_count + _hot_sample_count, _candidates.length()); } -void Candidates::add_candidate(nmethod* nm, int count) { - _candidates.append(Pair(nm, count)); -} - -void Candidates::add_hot_sample_count(int count) { +void Candidates::move_samples_to_hot(int count) { _hot_sample_count += count; -} - -void Candidates::add_non_profiled_sample_count(int count) { - _non_profiled_sample_count += count; + _non_profiled_sample_count -= count; } void Candidates::sort() { _candidates.sort( - [](Pair* a, Pair* b) { - if (a->second > b->second) return 1; - if (a->second < b->second) return -1; + [](Candidate* a, Candidate* b) { + if (a->get_sample_count() > b->get_sample_count()) return 1; + if (a->get_sample_count() < b->get_sample_count()) return -1; return 0; } ); @@ -115,14 +129,9 @@ bool Candidates::has_candidates() { return !_candidates.is_empty(); } -nmethod* Candidates::get_candidate() { +Candidate Candidates::get_candidate() { assert(has_candidates(), "must not be empty"); - Pair candidate = _candidates.pop(); - - _hot_sample_count += candidate.second; - _non_profiled_sample_count -= candidate.second; - - return candidate.first; + return _candidates.pop(); } double Candidates::get_hot_sample_percent() { diff --git a/src/hotspot/share/runtime/hotCodeSampler.hpp b/src/hotspot/share/runtime/hotCodeSampler.hpp index e6c2474b0682..83f396f7a7be 100644 --- a/src/hotspot/share/runtime/hotCodeSampler.hpp +++ b/src/hotspot/share/runtime/hotCodeSampler.hpp @@ -40,23 +40,46 @@ static inline uint rand_sampling_period_ms() { } class ThreadSampler; +class nmethod; + +class Candidate : public StackObj { + private: + nmethod* _nm; + int _compile_id; + int _sample_count; + + public: + Candidate() : _nm(nullptr), _compile_id(0), _sample_count(0) {} + Candidate(nmethod* nm, int compile_id, int samples_count) : _nm(nm), + _compile_id(compile_id), _sample_count(samples_count) {} + + nmethod* get_nmethod() const { + return _nm; + } + + int get_compile_id() const { + return _compile_id; + } + + int get_sample_count() const { + return _sample_count; + } +}; class Candidates : public StackObj { private: - GrowableArray> _candidates; + GrowableArray _candidates; int _hot_sample_count; int _non_profiled_sample_count; public: Candidates(ThreadSampler& sampler); - void add_candidate(nmethod* nm, int count); - void add_hot_sample_count(int count); - void add_non_profiled_sample_count(int count); + void move_samples_to_hot(int count); void sort(); bool has_candidates(); - nmethod* get_candidate(); + Candidate get_candidate(); double get_hot_sample_percent(); }; @@ -85,10 +108,15 @@ class ThreadSampler : public StackObj { static const int INITIAL_TABLE_SIZE = 109; // Table of nmethods found during profiling with sample count - ResizeableHashTable _samples; + // hash table: key = compile_id, value = Pair + ResizeableHashTable, AnyObj::C_HEAP, mtInternal> _samples; + + int _hot_sample_count; + int _non_profiled_sample_count; public: - ThreadSampler() : _samples(INITIAL_TABLE_SIZE, HotCodeSampleSeconds * 1000 / HotCodeMaxSamplingMs) {} + ThreadSampler() : _samples(INITIAL_TABLE_SIZE, HotCodeSampleSeconds * 1000 / HotCodeMaxSamplingMs), _hot_sample_count(0), + _non_profiled_sample_count(0) {} // Iterate over and sample all Java threads. Return false if sampling was interrupted by JFR sampling. bool sample_all_java_threads(); @@ -98,6 +126,14 @@ class ThreadSampler : public StackObj { void iterate_samples(Function func) { _samples.iterate_all(func); } + + int hot_sample_count() const { + return _hot_sample_count; + } + + int non_profiled_sample_count() const { + return _non_profiled_sample_count; + } }; #endif // SHARE_RUNTIME_HOTCODESAMPLER_HPP diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp index 8130bfbc1ebe..03d478c2a45c 100644 --- a/src/hotspot/share/runtime/init.cpp +++ b/src/hotspot/share/runtime/init.cpp @@ -22,6 +22,7 @@ * */ +#include "cds/aotMetaspace.hpp" #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "code/aotCodeCache.hpp" @@ -129,6 +130,7 @@ jint init_globals() { bytecodes_init(); classLoader_init1(); compilationPolicy_init(); + AOTMetaspace::get_aot_code_region_size(); codeCache_init(); VM_Version_init(); // depends on codeCache_init for emitting code VMRegImpl::set_regName(); // need this before generate_stubs (for printing oop maps). diff --git a/src/hotspot/share/runtime/java.cpp b/src/hotspot/share/runtime/java.cpp index cc4f25a2c5f0..057ce4240805 100644 --- a/src/hotspot/share/runtime/java.cpp +++ b/src/hotspot/share/runtime/java.cpp @@ -34,6 +34,7 @@ #include "classfile/stringTable.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" +#include "code/aotCodeCache.hpp" #include "code/codeCache.hpp" #include "compiler/compilationMemoryStatistic.hpp" #include "compiler/compilationPolicy.hpp" @@ -254,9 +255,12 @@ static void print_bytecode_count() {} // General statistics printing (profiling ...) -void print_statistics() { +void print_statistics_before_exit() { + LogStreamHandle(Info, aot, codecache, stats) aot_log; if (CITime) { CompileBroker::print_times(); + } else if (aot_log.is_enabled()) { + AOTCodeCache::print_timers_on(&aot_log); } #ifdef COMPILER1 @@ -289,6 +293,9 @@ void print_statistics() { if (PrintNMethodStatistics) { nmethod::print_statistics(); + AOTCodeCache::print_statistics_on(tty); + } else if (aot_log.is_enabled()) { + AOTCodeCache::print_statistics_on(&aot_log); } if (CountCompiledCalls) { print_method_invocation_histogram(); @@ -517,7 +524,7 @@ void before_exit(JavaThread* thread, bool halt) { } #endif - print_statistics(); + print_statistics_before_exit(); { MutexLocker ml(BeforeExit_lock); _before_exit_status = BEFORE_EXIT_DONE; diff --git a/src/hotspot/share/runtime/java.hpp b/src/hotspot/share/runtime/java.hpp index 2eb8d6b8eadc..db2f44f9622c 100644 --- a/src/hotspot/share/runtime/java.hpp +++ b/src/hotspot/share/runtime/java.hpp @@ -58,6 +58,8 @@ extern void vm_shutdown_during_initialization(const char* error, const char* mes extern void vm_exit_during_cds_dumping(const char* error, const char* message = nullptr); +extern void print_statistics_before_exit(); + // This is defined in linkType.cpp due to linking restraints extern bool is_vm_statically_linked(); diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index b0fa8af184db..9e9ac9c65cd2 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -3247,7 +3247,7 @@ void AdapterHandlerLibrary::lookup_aot_cache(AdapterHandlerEntry* handler) { const char* name = AdapterHandlerLibrary::name(handler); const uint32_t id = AdapterHandlerLibrary::id(handler); - CodeBlob* blob = AOTCodeCache::load_code_blob(AOTCodeEntry::Adapter, id, name); + CodeBlob* blob = AOTCodeCache::load_adapter(id, name); if (blob != nullptr) { handler->set_adapter_blob(blob->as_adapter_blob()); } @@ -3361,7 +3361,7 @@ bool AdapterHandlerLibrary::generate_adapter_code(AdapterHandlerEntry* handler, // try to save generated code const char* name = AdapterHandlerLibrary::name(handler); const uint32_t id = AdapterHandlerLibrary::id(handler); - bool success = AOTCodeCache::store_code_blob(*adapter_blob, AOTCodeEntry::Adapter, id, name); + bool success = AOTCodeCache::store_adapter(*adapter_blob, id, name); assert(success || !AOTCodeCache::is_dumping_adapter(), "caching of adapter must be disabled"); } #endif // ZERO diff --git a/src/hotspot/share/runtime/stubDeclarations.hpp b/src/hotspot/share/runtime/stubDeclarations.hpp index cc7f81309826..c8f215082e35 100644 --- a/src/hotspot/share/runtime/stubDeclarations.hpp +++ b/src/hotspot/share/runtime/stubDeclarations.hpp @@ -238,6 +238,7 @@ do_stub(monitor_notifyAll, 0, false, false) \ do_stub(rethrow, 2, true, true) \ do_stub(slow_arraycopy, 0, false, false) \ + do_stub(compile_method, 0, true, false) \ do_stub(register_finalizer, 0, false, false) \ do_stub(load_unknown_value, 0, true, false) \ do_stub(store_unknown_value, 0, true, false) \ diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index cdfbc629f02e..0f94937f67d6 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -35,6 +35,7 @@ #include "classfile/systemDictionary.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" +#include "code/aotCodeCache.hpp" #include "compiler/compileBroker.hpp" #include "compiler/compilerThread.hpp" #include "compiler/compileTask.hpp" @@ -839,6 +840,9 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) { initialize_class(vmSymbols::jdk_internal_vm_Continuation(), CHECK_JNI_ERR); } + // Pre-load AOT compiled methods + AOTCodeCache::preload_code(CHECK_JNI_ERR); + if (NativeHeapTrimmer::enabled()) { NativeHeapTrimmer::initialize(); } diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 68f61f08098f..d6b26f209f62 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -29,6 +29,7 @@ #include "classfile/javaThreadStatus.hpp" #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" +#include "code/aotCodeCache.hpp" #include "code/codeBlob.hpp" #include "code/codeCache.hpp" #include "code/compiledIC.hpp" @@ -544,8 +545,11 @@ nonstatic_field(nmethod, _immutable_data_size, int) \ nonstatic_field(nmethod, _compile_id, int) \ nonstatic_field(nmethod, _comp_level, CompLevel) \ + nonstatic_field(nmethod, _aot_code_entry, AOTCodeEntry*) \ volatile_nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \ \ + nonstatic_field(AOTCodeEntry, _for_preload, bool) \ + \ nonstatic_field(Deoptimization::UnrollBlock, _size_of_deoptimized_frame, int) \ nonstatic_field(Deoptimization::UnrollBlock, _caller_adjustment, int) \ nonstatic_field(Deoptimization::UnrollBlock, _number_of_frames, int) \ @@ -1107,6 +1111,7 @@ declare_toplevel_type(CompileTask) \ declare_toplevel_type(Deoptimization) \ declare_toplevel_type(Deoptimization::UnrollBlock) \ + declare_toplevel_type(AOTCodeEntry) \ \ /************************/ \ /* ImmutableOopMap */ \ diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index bdd5095376dd..6cf20285c569 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -49,7 +49,6 @@ #include "oops/instanceKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" -#include "oops/oopCast.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "prims/jvmtiAgentList.hpp" #include "runtime/fieldDescriptor.inline.hpp" diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 4c794c4d1795..587ae2afe226 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -45,7 +45,6 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" -#include "oops/oopCast.inline.hpp" #include "oops/typeArrayOop.inline.hpp" #include "runtime/arguments.hpp" #include "runtime/atomicAccess.hpp" diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index e3fd236c29f8..ecadbe845d7d 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -38,7 +38,6 @@ #include "oops/objArrayKlass.hpp" #include "oops/objArrayOop.inline.hpp" #include "oops/oop.inline.hpp" -#include "oops/oopCast.inline.hpp" #include "oops/oopHandle.inline.hpp" #include "oops/refArrayOop.inline.hpp" #include "oops/typeArrayOop.inline.hpp" diff --git a/src/hotspot/share/utilities/nativeStackPrinter.cpp b/src/hotspot/share/utilities/nativeStackPrinter.cpp index b243791c9339..f1fa9bdb7a38 100644 --- a/src/hotspot/share/utilities/nativeStackPrinter.cpp +++ b/src/hotspot/share/utilities/nativeStackPrinter.cpp @@ -45,7 +45,7 @@ void NativeStackPrinter::print_stack_from_frame(outputStream* st, frame fr, bool print_source_info, int max_frames) { // see if it's a valid frame if (fr.pc()) { - st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)"); + st->print_cr("Native frames: (J=compiled Java code, A=AOT compiled, P=AOT preloaded, j=interpreted, Vv=VM code, C=native code)"); const int limit = max_frames == -1 ? StackPrintLimit : MIN2(max_frames, StackPrintLimit); int count = 0; diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp index 23f985f9e4b8..6a3460ad8b34 100644 --- a/src/hotspot/share/utilities/vmError.cpp +++ b/src/hotspot/share/utilities/vmError.cpp @@ -329,7 +329,7 @@ void VMError::print_stack_trace(outputStream* st, JavaThread* jt, } #else if (jt->has_last_Java_frame()) { - st->print_cr("Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)"); + st->print_cr("Java frames: (J=compiled Java code, A=AOT compiled, P=AOT preloaded, j=interpreted, Vv=VM code)"); for (StackFrameStream sfs(jt, true /* update */, true /* process_frames */); !sfs.is_done(); sfs.next()) { sfs.current()->print_on_error(st, buf, buflen, verbose); st->cr(); diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index dae553ffd811..5fb58a57502b 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -5896,11 +5896,15 @@ public static MethodHandle foldArguments(MethodHandle target, MethodHandle combi * @param combiner method handle to call initially on the incoming arguments * @return method handle which incorporates the specified argument folding logic * @throws NullPointerException if either argument is null - * @throws IllegalArgumentException if either of the following two conditions holds: - * (1) {@code combiner}'s return type is non-{@code void} and not the same as the argument type at position - * {@code pos} of the target signature; - * (2) the {@code N} argument types at position {@code pos} of the target signature (skipping one matching - * the {@code combiner}'s return type) are not identical with the argument types of {@code combiner}. + * @throws IllegalArgumentException if any of the following conditions holds: + *
    + *
  1. {@code combiner}'s return type is non-{@code void} and not the same as the argument type at position + * {@code pos} of the target signature;
  2. + *
  3. the {@code N} argument types at position {@code pos} of the target signature (skipping one matching + * the {@code combiner}'s return type) are not identical with the argument types of {@code combiner};
  4. + *
  5. {@code pos} is negative or greater than the target's arity, or there are not sufficient arguments + * after {@code pos} in {@code target} to match {@code combiner}.
  6. + *
* * @see #foldArguments(MethodHandle, MethodHandle) * @since 9 @@ -5924,14 +5928,15 @@ private static Class foldArgumentChecks(int foldPos, MethodType targetType, M int foldArgs = combinerType.parameterCount(); Class rtype = combinerType.returnType(); int foldVals = rtype == void.class ? 0 : 1; + if (foldPos < 0 || foldPos > targetType.parameterCount() - foldVals - foldArgs) { + throw newIllegalArgumentException("position is out of range for target and combiner", foldPos); + } + boolean ok = true; int afterInsertPos = foldPos + foldVals; - boolean ok = (targetType.parameterCount() >= afterInsertPos + foldArgs); - if (ok) { - for (int i = 0; i < foldArgs; i++) { - if (combinerType.parameterType(i) != targetType.parameterType(i + afterInsertPos)) { - ok = false; - break; - } + for (int i = 0; i < foldArgs; i++) { + if (combinerType.parameterType(i) != targetType.parameterType(i + afterInsertPos)) { + ok = false; + break; } } if (ok && foldVals != 0 && combinerType.returnType() != targetType.parameterType(foldPos)) diff --git a/src/java.base/share/classes/java/math/BigDecimal.java b/src/java.base/share/classes/java/math/BigDecimal.java index 3cfe18e84c30..0a7ed29bc0e5 100644 --- a/src/java.base/share/classes/java/math/BigDecimal.java +++ b/src/java.base/share/classes/java/math/BigDecimal.java @@ -100,7 +100,7 @@ * used in the result's representation. * * The different representations of the same numerical value are - * called members of the same cohort. The {@linkplain + * called members of the same {@index cohort}. The {@linkplain * compareTo(BigDecimal) natural order} of {@code BigDecimal} * considers members of the same cohort to be equal to each other. In * contrast, the {@link equals equals} method requires both the @@ -109,6 +109,12 @@ * #unscaledValue()} will differ for numerically equal values with * different representations. * + *

In the terminology {@linkplain Double##fpNumericalEq discussed + * for binary floating-point}, {@code BigDecimal.equals} uses + * representation equivalence while {@code BigDecimal.compareTo} + * uses numerical equality to compare members of the same + * cohort. + * *

In general the rounding modes and precision setting determine * how operations return results with a limited number of digits when * the exact result has more digits (perhaps infinitely many in the @@ -3228,7 +3234,9 @@ else if (ys != INFLATED) /** * Compares this {@code BigDecimal} with the specified {@code - * Object} for equality. Unlike {@link #compareTo(BigDecimal) + * Object} for equality using {@linkplain Double##fpNumericalEq + * representation equivalence}. + * Unlike {@link #compareTo(BigDecimal) * compareTo}, this method considers two {@code BigDecimal} * objects equal only if they are equal in value and * scale. Therefore 2.0 is not equal to 2.00 when compared by this @@ -3244,9 +3252,6 @@ else if (ys != INFLATED) * HALF_UP)} which evaluates to 0.7 and
* {@code new BigDecimal("2.00").divide(BigDecimal.valueOf(3), * HALF_UP)} which evaluates to 0.67. - * The behavior of this method is analogous to checking the - * {@linkplain Double##repEquivalence representation equivalence} - * of {@code double} values. * * @param x {@code Object} to which this {@code BigDecimal} is * to be compared. @@ -3594,8 +3599,12 @@ boolean isInteger() { * @jls 5.1.3 Narrowing Primitive Conversion */ public BigInteger toBigInteger() { - // force to an integer, quietly - return this.setScale(0, ROUND_DOWN).inflated(); + if (signum() == 0 || // Numerical zero + (scale() >= precision()) ) { // Only fractional digits + return BigInteger.ZERO; + } else { // force to an integer, quietly + return this.setScale(0, ROUND_DOWN).inflated(); + } } /** @@ -3609,8 +3618,13 @@ public BigInteger toBigInteger() { * @since 1.5 */ public BigInteger toBigIntegerExact() { - // round to an integer, with Exception if decimal part non-0 - return this.setScale(0, ROUND_UNNECESSARY).inflated(); + if (signum() == 0) { // Numerical zero + return BigInteger.ZERO; + } else if ((scale() >= precision()) ) { // Quick check for only fractional digits + throw new ArithmeticException("Rounding necessary; only fractional digits"); + } else { // round to an integer, with Exception if fractional part non-0 + return this.setScale(0, ROUND_UNNECESSARY).inflated(); + } } /** diff --git a/src/java.base/share/classes/java/nio/file/FileChannelLinesSpliterator.java b/src/java.base/share/classes/java/nio/file/FileChannelLinesSpliterator.java index 36e463ba6168..d80aca3fcdd5 100644 --- a/src/java.base/share/classes/java/nio/file/FileChannelLinesSpliterator.java +++ b/src/java.base/share/classes/java/nio/file/FileChannelLinesSpliterator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, 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 @@ -36,6 +36,7 @@ import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.nio.charset.Charset; +import java.util.Objects; import java.util.Set; import java.util.Spliterator; import java.util.concurrent.atomic.AtomicInteger; @@ -114,6 +115,7 @@ private FileChannelLinesSpliterator(FileChannel fc, Charset cs, int index, @Override public boolean tryAdvance(Consumer action) { + Objects.requireNonNull(action); String line = readLine(); if (line != null) { action.accept(line); @@ -125,6 +127,7 @@ public boolean tryAdvance(Consumer action) { @Override public void forEachRemaining(Consumer action) { + Objects.requireNonNull(action); String line; while ((line = readLine()) != null) { action.accept(line); diff --git a/src/java.base/share/classes/java/text/SimpleDateFormat.java b/src/java.base/share/classes/java/text/SimpleDateFormat.java index 66bbd55192a3..1c45b4a249aa 100644 --- a/src/java.base/share/classes/java/text/SimpleDateFormat.java +++ b/src/java.base/share/classes/java/text/SimpleDateFormat.java @@ -41,6 +41,8 @@ import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; +import java.time.Instant; +import java.time.LocalDateTime; import java.time.ZoneOffset; import java.util.Calendar; import java.util.Date; @@ -1303,20 +1305,7 @@ private void subFormat(int patternCharIndex, int count, int zoneOffset = calendar.get(Calendar.ZONE_OFFSET); int dstOffset = calendar.get(Calendar.DST_OFFSET) + zoneOffset; - ZoneOffset explicitDstOffset = null; - // Check if an explicit metazone DST offset exists. - // Only check against instances of ZoneInfo, since the standard JDK timezones - // are guaranteed to extend this internal type. - if (tz instanceof ZoneInfo zi) { - explicitDstOffset = TimeZoneNameUtility.explicitDstOffset(tzid); - if (explicitDstOffset != null) { - // The time zone ID has an explicit dst offset. Ensure that - // our current TimeZone is canonical. - if (!ZoneInfo.hasCanonicalRule(zi)) { - explicitDstOffset = null; - } - } - } + ZoneOffset explicitDstOffset = getExplicitDstOffset(tz); boolean daylight = explicitDstOffset != null ? dstOffset == explicitDstOffset.getTotalSeconds() * 1_000 : dstOffset != zoneOffset; @@ -1528,6 +1517,7 @@ public Date parse(String text, ParsePosition pos) int textLength = text.length(); boolean[] ambiguousYear = {false}; + int[] matchedName = {0}; CalendarBuilder calb = new CalendarBuilder(); @@ -1599,7 +1589,7 @@ public Date parse(String text, ParsePosition pos) } } start = subParse(text, start, tag, count, obeyCount, - ambiguousYear, pos, + ambiguousYear, matchedName, pos, useFollowingMinusSignAsDelimiter, calb); if (start < 0) { pos.index = oldStart; @@ -1616,12 +1606,15 @@ public Date parse(String text, ParsePosition pos) Date parsedDate; try { - parsedDate = calb.establish(calendar).getTime(); + parsedDate = resolveExplicitDstOffset( + calb, matchedName, calb.establish(calendar).getTime()); + // If the year value is ambiguous, // then the two-digit year == the default start year if (ambiguousYear[0]) { if (parsedDate.before(defaultCenturyStart)) { - parsedDate = calb.addYear(100).establish(calendar).getTime(); + parsedDate = resolveExplicitDstOffset(calb, + matchedName, calb.addYear(100).establish(calendar).getTime()); } } } @@ -1788,7 +1781,7 @@ private boolean matchDSTString(String text, int start, int zoneIndex, int standa * find time zone 'text' matched zoneStrings and set to internal * calendar. */ - private int subParseZoneString(String text, int start, CalendarBuilder calb) { + private int subParseZoneString(String text, int start, CalendarBuilder calb, int[] matchedName) { boolean useSameName = false; // true if standard and daylight time use the same abbreviation. TimeZone currentTimeZone = getTimeZone(); @@ -1840,15 +1833,30 @@ private int subParseZoneString(String text, int start, CalendarBuilder calb) { if (!tz.equals(currentTimeZone)) { setTimeZone(tz); } - // If the time zone matched uses the same name - // (abbreviation) for both standard and daylight time, - // let the time zone in the Calendar decide which one. - // - // Also if tz.getDSTSaving() returns 0 for DST, use tz to - // determine the local time. (6645292) - int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0; - if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) { - calb.clear(Calendar.ZONE_OFFSET).set(Calendar.DST_OFFSET, dstAmount); + matchedName[0] = 0; + ZoneOffset explicitDstOffset = getExplicitDstOffset(tz); + // If we have an explicit dstOffset, let the zone rules determine + // the eventual offset instead of the parsed zone name from the text. + // Note that we retain the matched name to handle the transition period. + if (explicitDstOffset == null) { + // If the time zone matched uses the same name + // (abbreviation) for both standard and daylight time, + // let the time zone in the Calendar decide which one. + // + // Also if tz.getDSTSaving() returns 0 for DST, use tz to + // determine the local time. (6645292) + int dstAmount = (nameIndex >= 3) ? tz.getDSTSavings() : 0; + if (!(useSameName || (nameIndex >= 3 && dstAmount == 0))) { + calb.clear(Calendar.ZONE_OFFSET).set(Calendar.DST_OFFSET, dstAmount); + } + } else { + // If the names are identical, they cannot be used to help resolve + // the correct offset during the transition period. (Practically, this + // will likely never happen for an explicit dstOffset CLDR zone). + if (!useSameName) { + matchedName[0] = nameIndex < 3 ? 1 : 2; + calb.clear(Calendar.ZONE_OFFSET).clear(Calendar.DST_OFFSET); + } } return (start + zoneNames[nameIndex].length()); } @@ -1941,6 +1949,9 @@ private boolean isDigit(char c) { * and we should use the count to know when to stop parsing. * @param ambiguousYear return parameter; upon return, if ambiguousYear[0] * is true, then a two-digit year was parsed and may need to be readjusted. + * @param matchedName return parameter; upon return, if matchedName[0] + * is 0, then either the names were identical or no name was matched. If + * 1, then a standard name was matched, and if 2, then a daylight name was matched. * @param origPos origPos.errorIndex is used to return an error index * at which a parse error occurred, if matching failure occurs. * @return the new start position if matching succeeded; -1 indicating @@ -1948,7 +1959,7 @@ private boolean isDigit(char c) { * an error index is set to origPos.errorIndex. */ private int subParse(String text, int start, int patternCharIndex, int count, - boolean obeyCount, boolean[] ambiguousYear, + boolean obeyCount, boolean[] ambiguousYear, int[] matchedName, ParsePosition origPos, boolean useFollowingMinusSignAsDelimiter, CalendarBuilder calb) { Number number; @@ -2233,7 +2244,7 @@ private int subParse(String text, int start, int patternCharIndex, int count, } else { // Try parsing the text as a time zone // name or abbreviation. - int i = subParseZoneString(text, pos.index, calb); + int i = subParseZoneString(text, pos.index, calb, matchedName); if (i > 0) { return i; } @@ -2551,6 +2562,59 @@ private Map getDisplayContextNamesMap(int field, Locale locale) return map; } + /** + * Obtains the dstOffset for a time zone if it exists, otherwise null. + */ + private ZoneOffset getExplicitDstOffset(TimeZone tz) { + ZoneOffset explicitDstOffset = null; + // Check if an explicit metazone DST offset exists. + // Only check against instances of ZoneInfo, since the standard JDK timezones + // are guaranteed to extend this internal type. + if (tz instanceof ZoneInfo zi) { + explicitDstOffset = TimeZoneNameUtility.explicitDstOffset(tz.getID()); + if (explicitDstOffset != null) { + // The time zone ID has an explicit dst offset. Ensure that + // our current TimeZone is canonical. + if (!ZoneInfo.hasCanonicalRule(zi)) { + explicitDstOffset = null; + } + } + } + return explicitDstOffset; + } + + /** + * Apply the explicit dst offset if the zone is applicable and is needed to resolve + * an ambiguous date during a transition period. This method does nothing to the passed date + * if none of the preconditions are relevant, which occurs for the majority of cases. + */ + private Date resolveExplicitDstOffset(CalendarBuilder calb, int[] matchedName, Date parsedDate) { + // For explicit dstOffset cases, we need to use the name in the text + // to determine which offset to use during transition periods. + var tz = calendar.getTimeZone(); + ZoneOffset explicitDstOffset; + if (!calb.isSet(Calendar.ZONE_OFFSET) && matchedName[0] != 0 + && (explicitDstOffset = getExplicitDstOffset(tz)) != null) { + var ldt = LocalDateTime.ofInstant(parsedDate.toInstant(), tz.toZoneId()); + var offs = tz.toZoneId().getRules().getValidOffsets(ldt); + // If size is 2, then we have multiple offsets at the date, implying + // a transition period. Pick the offset that aligns with the matched name. + if (offs.size() == 2 && offs.contains(explicitDstOffset)) { + if (matchedName[0] == 1) { + // standard + var stdOffset = explicitDstOffset.equals(offs.get(0)) ? + offs.get(1) : offs.get(0); + parsedDate = Date.from(Instant.from(ldt.atOffset(stdOffset))); + } else if (matchedName[0] == 2) { + // daylight + parsedDate = Date.from(Instant.from(ldt.atOffset(explicitDstOffset))); + } + calendar.setTime(parsedDate); + } + } + return parsedDate; + } + /** * After reading an object from the input stream, the format * pattern in the object is verified. diff --git a/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java b/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java index 980ff77d83a5..6237c55df3fd 100644 --- a/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java +++ b/src/java.base/share/classes/javax/net/ssl/ExtendedSSLSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 2026, 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 @@ -94,6 +94,30 @@ public ExtendedSSLSession() {} */ public abstract String[] getPeerSupportedSignatureAlgorithms(); + /** + * Returns the key exchange named group negotiated for this session. + *

+ * The standard named groups are defined in the + * + * Named Groups section of the Java Security Standard Algorithm Names + * Specification. Other named groups supported by the provider can also be + * returned. + * + * @implSpec The default implementation throws + * {@code UnsupportedOperationException}. + * @return the negotiated key exchange named group, or {@code null} + * if no named group was negotiated or the handshake has not + * completed + * @throws UnsupportedOperationException if the underlying provider does + * not implement the operation + * @spec security/standard-names.html Java Security Standard Algorithm Names + * @since 28 + */ + public String getNamedGroup() { + throw new UnsupportedOperationException( + "Underlying provider does not implement the method"); + } + /** * Obtains a {@link List} containing all {@link SNIServerName}s * of the requested Server Name Indication (SNI) extension. diff --git a/src/java.base/share/classes/javax/net/ssl/SSLEngine.java b/src/java.base/share/classes/javax/net/ssl/SSLEngine.java index 9376b7d18765..e707ef3fc6d3 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLEngine.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLEngine.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -1484,4 +1484,33 @@ public void setHandshakeApplicationProtocolSelector( getHandshakeApplicationProtocolSelector() { throw new UnsupportedOperationException(); } + + /** + * Returns the names of the named groups which could be enabled for use + * on this engine. + *

+ * The returned array includes named groups from the list of standard + * named group names in the + * + * Named Groups section of the Java Security Standard Algorithm Names + * Specification, and may also include other named groups that the provider + * supports. + *

+ * To get the names of the named groups which are currently enabled for use + * on this engine, call {@link SSLParameters#getNamedGroups()}, + * accessible through {@link #getSSLParameters()}. + * + * @implSpec The implementation in this class throws + * {@code UnsupportedOperationException} and performs no other + * action. + * @return an array of named group names + * @throws UnsupportedOperationException if the underlying provider + * does not implement the operation. + * @spec security/standard-names.html Java Security Standard Algorithm Names + * @since 28 + */ + public String [] getSupportedNamedGroups() { + throw new UnsupportedOperationException( + "Underlying provider does not implement the method"); + } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java b/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java index 71cb304edbcd..0e4d0651e49e 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLServerSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -529,4 +529,33 @@ public void setSSLParameters(SSLParameters params) { } } + /** + * Returns the names of the named groups which could be enabled for use + * on an SSL connection. + *

+ * The returned array includes named groups from the list of standard + * named group names in the + * + * Named Groups section of the Java Security Standard Algorithm Names + * Specification, and may also include other named groups that the provider + * supports. + *

+ * To get the names of the named groups which are currently enabled for use + * by newly accepted connections, + * call {@link SSLParameters#getNamedGroups()}, accessible through + * {@link #getSSLParameters()}. + * + * @implSpec The implementation in this class throws + * {@code UnsupportedOperationException} and performs no other + * action. + * @return an array of named group names + * @throws UnsupportedOperationException if the underlying provider + * does not implement the operation. + * @spec security/standard-names.html Java Security Standard Algorithm Names + * @since 28 + */ + public String [] getSupportedNamedGroups() { + throw new UnsupportedOperationException( + "Underlying provider does not implement the method"); + } } diff --git a/src/java.base/share/classes/javax/net/ssl/SSLSocket.java b/src/java.base/share/classes/javax/net/ssl/SSLSocket.java index 117f2de9bbc6..3ae7cd72c673 100644 --- a/src/java.base/share/classes/javax/net/ssl/SSLSocket.java +++ b/src/java.base/share/classes/javax/net/ssl/SSLSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, 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 @@ -872,4 +872,33 @@ public void setHandshakeApplicationProtocolSelector( getHandshakeApplicationProtocolSelector() { throw new UnsupportedOperationException(); } + + /** + * Returns the names of the named groups which could be enabled for use + * on this connection. + *

+ * The returned array includes named groups from the list of standard + * named group names in the + * + * Named Groups section of the Java Security Standard Algorithm Names + * Specification, and may also include other named groups that the provider + * supports. + *

+ * To get the names of the named groups which are currently enabled for use + * on this connection, call {@link SSLParameters#getNamedGroups()}, + * accessible through {@link #getSSLParameters()}. + * + * @implSpec The implementation in this class throws + * {@code UnsupportedOperationException} and performs no other + * action. + * @return an array of named group names + * @throws UnsupportedOperationException if the underlying provider + * does not implement the operation. + * @spec security/standard-names.html Java Security Standard Algorithm Names + * @since 28 + */ + public String [] getSupportedNamedGroups() { + throw new UnsupportedOperationException( + "Underlying provider does not implement the method"); + } } diff --git a/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java b/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java deleted file mode 100644 index dbf21601c53a..000000000000 --- a/src/java.base/share/classes/jdk/internal/foreign/BufferStack.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 jdk.internal.foreign; - -import jdk.internal.misc.CarrierThreadLocal; -import jdk.internal.vm.annotation.ForceInline; - -import java.lang.foreign.Arena; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.ref.Reference; -import java.util.concurrent.locks.ReentrantLock; -import java.util.function.Consumer; - -/** - * A buffer stack that allows efficient reuse of memory segments. This is useful in cases - * where temporary memory is needed. - *

- * Use the factories {@code BufferStack.of(...)} to create new instances of this class. - *

- * Note: The reused segments are neither zeroed out before nor after re-use. - */ -public final class BufferStack { - - private final long byteSize; - private final long byteAlignment; - private final CarrierThreadLocal tl; - - private BufferStack(long byteSize, long byteAlignment) { - this.byteSize = byteSize; - this.byteAlignment = byteAlignment; - this.tl = new CarrierThreadLocal<>() { - @Override - protected BufferStack.PerThread initialValue() { - return BufferStack.PerThread.of(byteSize, byteAlignment); - } - }; - } - - /** - * {@return a new Arena that tries to provide {@code byteSize} and {@code byteAlignment} - * allocations by recycling the BufferStack's internal memory} - * - * @param byteSize to be reserved from this BufferStack's internal memory - * @param byteAlignment to be used for reservation - */ - @ForceInline - public Arena pushFrame(long byteSize, long byteAlignment) { - return tl.get().pushFrame(byteSize, byteAlignment); - } - - /** - * {@return a new Arena that tries to provide {@code byteSize} - * allocations by recycling the BufferStack's internal memory} - * - * @param byteSize to be reserved from this BufferStack's internal memory - */ - @ForceInline - public Arena pushFrame(long byteSize) { - return pushFrame(byteSize, 1); - } - - /** - * {@return a new Arena that tries to provide {@code layout} - * allocations by recycling the BufferStack's internal memory} - * - * @param layout for which to reserve internal memory - */ - @ForceInline - public Arena pushFrame(MemoryLayout layout) { - return pushFrame(layout.byteSize(), layout.byteAlignment()); - } - - @Override - public String toString() { - return "BufferStack[byteSize=" + byteSize + ", byteAlignment=" + byteAlignment + "]"; - } - - private record PerThread(ReentrantLock lock, - Arena arena, - SlicingAllocator stack, - CleanupAction cleanupAction) { - - @ForceInline - public Arena pushFrame(long size, long byteAlignment) { - boolean needsLock = Thread.currentThread().isVirtual() && !lock.isHeldByCurrentThread(); - if (needsLock && !lock.tryLock()) { - // Rare: another virtual thread on the same carrier competed for acquisition. - return Arena.ofConfined(); - } - if (!stack.canAllocate(size, byteAlignment)) { - if (needsLock) lock.unlock(); - return Arena.ofConfined(); - } - return new Frame(needsLock, size, byteAlignment); - } - - static PerThread of(long byteSize, long byteAlignment) { - final Arena arena = Arena.ofAuto(); - return new PerThread(new ReentrantLock(), - arena, - new SlicingAllocator(arena.allocate(byteSize, byteAlignment)), - new CleanupAction(arena)); - } - - private record CleanupAction(Arena arena) implements Consumer { - @Override - public void accept(MemorySegment memorySegment) { - Reference.reachabilityFence(arena); - } - } - - private final class Frame implements Arena { - - private final boolean locked; - private final long parentOffset; - private final long topOfStack; - private final Arena confinedArena; - private final SegmentAllocator frame; - - @SuppressWarnings("restricted") - @ForceInline - public Frame(boolean locked, long byteSize, long byteAlignment) { - this.locked = locked; - this.parentOffset = stack.currentOffset(); - final MemorySegment frameSegment = stack.allocate(byteSize, byteAlignment); - this.topOfStack = stack.currentOffset(); - this.confinedArena = Arena.ofConfined(); - // The cleanup action will keep the original automatic `arena` (from which - // the reusable segment is first allocated) alive even if this Frame - // becomes unreachable but there are reachable segments still alive. - this.frame = new SlicingAllocator(frameSegment.reinterpret(confinedArena, cleanupAction)); - } - - @ForceInline - private void assertOrder() { - if (topOfStack != stack.currentOffset()) - throw new IllegalStateException("Out of order access: frame not top-of-stack"); - } - - @ForceInline - @Override - @SuppressWarnings("restricted") - public MemorySegment allocate(long byteSize, long byteAlignment) { - // Make sure we are on the right thread and not closed - MemorySessionImpl.toMemorySession(confinedArena).checkValidState(); - return frame.allocate(byteSize, byteAlignment); - } - - @ForceInline - @Override - public MemorySegment.Scope scope() { - return confinedArena.scope(); - } - - @ForceInline - @Override - public void close() { - assertOrder(); - // the Arena::close method is called "early" as it checks thread - // confinement and crucially before any mutation of the internal - // state takes place. - confinedArena.close(); - stack.resetTo(parentOffset); - if (locked) { - lock.unlock(); - } - } - } - } - - public static BufferStack of(long byteSize, long byteAlignment) { - if (byteSize < 0) { - throw new IllegalArgumentException("Negative byteSize: " + byteSize); - } - if (byteAlignment < 0) { - throw new IllegalArgumentException("Negative byteAlignment: " + byteAlignment); - } - return new BufferStack(byteSize, byteAlignment); - } - - public static BufferStack of(long byteSize) { - return new BufferStack(byteSize, 1); - } - - public static BufferStack of(MemoryLayout layout) { - // Implicit null check - return of(layout.byteSize(), layout.byteAlignment()); - } -} diff --git a/src/java.base/share/classes/jdk/internal/foreign/CaptureStateUtil.java b/src/java.base/share/classes/jdk/internal/foreign/CaptureStateUtil.java deleted file mode 100644 index b3a19340fb54..000000000000 --- a/src/java.base/share/classes/jdk/internal/foreign/CaptureStateUtil.java +++ /dev/null @@ -1,378 +0,0 @@ -/* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 jdk.internal.foreign; - -import jdk.internal.invoke.MhUtil; -import jdk.internal.vm.annotation.ForceInline; - -import java.lang.foreign.Arena; -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.StructLayout; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.invoke.VarHandle; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.function.Function; -import java.util.function.IntFunction; - -/** - * An internal utility class that can be used to adapt system-call-styled method handles - * for efficient and easy use. - */ -public final class CaptureStateUtil { - - private static final StructLayout CAPTURE_LAYOUT = Linker.Option.captureStateLayout(); - private static final BufferStack POOL = BufferStack.of(CAPTURE_LAYOUT); - - // The `BASIC_HANDLE_CACHE` contains the common "basic handles" that can be reused for - // all adapted method handles. Keeping as much as possible reusable reduces the number - // of combinators needed to form an adapted method handle. - // The function is lazily computed. - // - private static final Map SEGMENT_EXTRACTION_HANDLE_CACHE; - - static { - final Set inputs = new HashSet<>(); - // The Cartesian product : (int.class, long.class) x ("errno", ...) - // Do not use Streams in order to enable "early" use in the init sequence. - for (Class c : new Class[]{int.class, long.class}) { - for (MemoryLayout layout : CAPTURE_LAYOUT.memberLayouts()) { - inputs.add(new SegmentExtractorKey(c, layout.name().orElseThrow())); - } - } - - // Do not use a lambda in order to allow early use in the init sequence - final Function segmentExtractionHandle = new Function<>() { - @Override - public MethodHandle apply(SegmentExtractorKey basicKey) { - return makeSegmentExtractionHandle(basicKey); - } - }; - - SEGMENT_EXTRACTION_HANDLE_CACHE = Map.ofLazy(inputs, segmentExtractionHandle); - } - - // A key that holds both the `returnType` and the `stateName` needed to look up a - // specific "basic handle" in the `BASIC_HANDLE_CACHE`. - // returnType in {int.class | long.class} - // stateName can be anything non-null but should be in {"GetLastError" | "WSAGetLastError" | "errno"} - private record SegmentExtractorKey(Class returnType, String stateName) { - - SegmentExtractorKey(MethodHandle target, String stateName) { - this(returnType(target), Objects.requireNonNull(stateName)); - } - - static Class returnType(MethodHandle target) { - // Implicit null check - final MethodType type = target.type(); - final Class returnType = type.returnType(); - - if (!(returnType.equals(int.class) || returnType.equals(long.class))) { - throw illegalArgDoesNot(target, "return an int or a long"); - } - if (type.parameterCount() == 0 || type.parameterType(0) != MemorySegment.class) { - throw illegalArgDoesNot(target, "have a MemorySegment as the first parameter"); - } - return returnType; - } - - private static IllegalArgumentException illegalArgDoesNot(MethodHandle target, String info) { - return new IllegalArgumentException("The provided target " + target - + " does not " + info); - } - - } - - private CaptureStateUtil() {} - - /** - * {@return a new MethodHandle that adapts the provided {@code target} so that it - * directly returns the same value as the {@code target} if it is non-negative, - * otherwise returns the negated captured state defined by the provided - * {@code stateName}} - *

- * This method is suitable for adapting system-call method handles(e.g. - * {@code open()}, {@code read()}, and {@code close()}). Clients can check the return - * value as shown in this example: - * {@snippet lang = java: - * // (MemorySegment capture, MemorySegment pathname, int flags)int - * static final MethodHandle CAPTURING_OPEN = ... - * - * // (MemorySegment pathname, int flags)int - * static final MethodHandle OPEN = CaptureStateUtil - * .adaptSystemCall(CAPTURING_OPEN, "errno"); - * - * try { - * int fh = (int)OPEN.invokeExact(pathName, flags); - * if (fh < 0) { - * throw new IOException("Error opening file: errno = " + (-fh)); - * } - * processFile(fh); - * } catch (Throwable t) { - * throw new RuntimeException(t); - * } - * - *} - * - * For a {@code target} method handle that takes a {@code MemorySegment} and two - * {@code int} parameters and returns an {@code int} value, the method returns a new - * method handle that is doing the equivalent of: - *

- * {@snippet lang = java: - * private static final MemoryLayout CAPTURE_LAYOUT = - * Linker.Option.captureStateLayout(); - * private static final BufferStack POOL = - * BufferStack.of(CAPTURE_LAYOUT); - * - * public int invoke(MethodHandle target, - * String stateName, - * int a, int b) { - * try (var arena = POOL.pushFrame(CAPTURE_LAYOUT)) { - * final MemorySegment segment = arena.allocate(CAPTURE_LAYOUT); - * final int result = (int) handle.invoke(segment, a, b); - * if (result >= 0) { - * return result; - * } - * return -(int) CAPTURE_LAYOUT - * .varHandle(MemoryLayout.PathElement.groupElement(stateName)) - * .get(segment, 0); - * } - * } - *} - * except it is more performant. In the above {@code stateName} is the name of the - * captured state (e.g. {@code errno}). The static {@code CAPTURE_LAYOUT} is shared - * across all target method handles adapted by this method. - * - * @param target method handle that returns an {@code int} or a {@code long} and - * has a capturing state MemorySegment as its first parameter - * @param stateName the name of the capturing state member layout (i.e. "errno", - * "GetLastError", or "WSAGetLastError") - * @throws IllegalArgumentException if the provided {@code target}'s return type is - * not {@code int} or {@code long} - * @throws IllegalArgumentException if the provided {@code target}'s first parameter - * type is not {@linkplain MemorySegment} - * @throws IllegalArgumentException if the provided {@code stateName} is unknown on - * the current platform - */ - public static MethodHandle adaptSystemCall(MethodHandle target, - String stateName) { - // Invariants checked in the BasicKey record - final SegmentExtractorKey key = new SegmentExtractorKey(target, stateName); - - // ((int | long), MemorySegment)(int | long) - final MethodHandle segmentExtractor = SEGMENT_EXTRACTION_HANDLE_CACHE.get(key); - if (segmentExtractor == null) { - throw new IllegalArgumentException("Input not allowed: " + key); - } - - // Make `target` specific adaptations of the basic handle - - // Pre-pend all the parameters from the `target` MH. - // (C0=MemorySegment, C1-Cn, MemorySegment)(int|long) - MethodHandle innerAdapted = MethodHandles.collectArguments(segmentExtractor, 0, target); - - final int[] perm = new int[target.type().parameterCount() + 1]; - for (int i = 0; i < target.type().parameterCount(); i++) { - perm[i] = i; - } - // Last takes first - perm[perm.length - 1] = 0; - // Deduplicate the first and last coordinate and only use the first one. - // (C0=MemorySegment, C1-Cn)(int|long) - innerAdapted = MethodHandles.permuteArguments(innerAdapted, target.type(), perm); - - // Use an `Arena` for the first argument instead and extract a segment from it. - // (C0=Arena, C1-Cn)(int|long) - innerAdapted = MethodHandles.collectArguments(innerAdapted, 0, HANDLES_CACHE.get(ALLOCATE)); - - // Add an identity function for the result of the cleanup action. - // ((int|long))(int|long) - MethodHandle cleanup = MethodHandles.identity(key.returnType()); - // Add a dummy `Throwable` argument for the cleanup action. - // This means, anything thrown will just be propagated. - // (Throwable, (int|long))(int|long) - cleanup = MethodHandles.dropArguments(cleanup, 0, Throwable.class); - // Add the first `Arena` parameter of the `innerAdapted` method handle to the - // cleanup action and invoke `Arena::close` when it is run. The `cleanup` handle - // does not have to have all parameters. It can have zero or more. - // (Throwable, (int|long), Arena)(int|long) - cleanup = MethodHandles.collectArguments(cleanup, 2, HANDLES_CACHE.get(ARENA_CLOSE)); - - // Combine the `innerAdapted` and `cleanup` action into a try/finally block. - // (Arena, C1-Cn)(int|long) - final MethodHandle tryFinally = MethodHandles.tryFinally(innerAdapted, cleanup); - - // Acquire the arena from the global pool. - // With this, we finally arrive at the intended method handle: - // (C1-Cn)(int|long) - return MethodHandles.collectArguments(tryFinally, 0, HANDLES_CACHE.get(ACQUIRE_ARENA)); - } - - private static MethodHandle makeSegmentExtractionHandle(SegmentExtractorKey segmentExtractorKey) { - final VarHandle vh = CAPTURE_LAYOUT.varHandle( - MemoryLayout.PathElement.groupElement(segmentExtractorKey.stateName())); - // This MH is used to extract the named captured state - // from the capturing `MemorySegment`. - // (MemorySegment, long)int - MethodHandle intExtractor = vh.toMethodHandle(VarHandle.AccessMode.GET); - // As the MH is already adapted to use the appropriate - // offset, we just insert `0L` for the offset. - // (MemorySegment)int - intExtractor = MethodHandles.insertArguments(intExtractor, 1, 0L); - - // If X is the `returnType` (either `int` or `long`) then - // the code below is equivalent to: - // - // X handle(X returnValue, MemorySegment segment) - // if (returnValue >= 0) { - // // Ignore the segment - // return returnValue; - // } else { - // // ignore the returnValue - // return -(X)intExtractor.invokeExact(segment); - // } - // } - if (segmentExtractorKey.returnType().equals(int.class)) { - // (int, MemorySegment)int - return MethodHandles.guardWithTest( - HANDLES_CACHE.get(NON_NEGATIVE_INT), - HANDLES_CACHE.get(SUCCESS_INT), - HANDLES_CACHE.get(ERROR_INT).bindTo(intExtractor)); - } else { - // (long, MemorySegment)long - return MethodHandles.guardWithTest( - HANDLES_CACHE.get(NON_NEGATIVE_LONG), - HANDLES_CACHE.get(SUCCESS_LONG), - HANDLES_CACHE.get(ERROR_LONG).bindTo(intExtractor)); - } - } - - // The methods below are reflective used via static MethodHandles - - @ForceInline - private static Arena acquireArena() { - return POOL.pushFrame(CAPTURE_LAYOUT); - } - - @ForceInline - private static MemorySegment allocate(Arena arena) { - return arena.allocate(CAPTURE_LAYOUT.byteSize(), CAPTURE_LAYOUT.byteAlignment()); - } - - @ForceInline - private static boolean nonNegative(int value) { - return value >= 0; - } - - @ForceInline - private static int success(int value, - MemorySegment segment) { - return value; - } - - @ForceInline - private static int error(MethodHandle errorHandle, - int value, - MemorySegment segment) throws Throwable { - return -(int) errorHandle.invokeExact(segment); - } - - @ForceInline - private static boolean nonNegative(long value) { - return value >= 0L; - } - - @ForceInline - private static long success(long value, - MemorySegment segment) { - return value; - } - - @ForceInline - private static long error(MethodHandle errorHandle, - long value, - MemorySegment segment) throws Throwable { - return -(int) errorHandle.invokeExact(segment); - } - - // The method handles below are bound to static methods residing in this class - - private static final int - NON_NEGATIVE_INT = 0, - SUCCESS_INT = 1, - ERROR_INT = 2, - NON_NEGATIVE_LONG = 3, - SUCCESS_LONG = 4, - ERROR_LONG = 5, - ACQUIRE_ARENA = 6, - ALLOCATE = 7, - ARENA_CLOSE = 8; - - // Do not use a lambda in order to allow early use in the init sequence - private static final IntFunction UNDERLYING_MAKE_HANDLE = new IntFunction() { - @Override - public MethodHandle apply(int value) { - return makeHandle(value); - } - }; - - private static final List HANDLES_CACHE = - List.ofLazy(ARENA_CLOSE + 1, UNDERLYING_MAKE_HANDLE); - - private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); - - private static MethodHandle makeHandle(int index) { - return switch (index) { - case NON_NEGATIVE_INT -> MhUtil.findStatic(LOOKUP, "nonNegative", - MethodType.methodType(boolean.class, int.class)); - case SUCCESS_INT -> MhUtil.findStatic(LOOKUP, "success", - MethodType.methodType(int.class, int.class, MemorySegment.class)); - case ERROR_INT -> MhUtil.findStatic(LOOKUP, "error", - MethodType.methodType(int.class, MethodHandle.class, int.class, MemorySegment.class)); - case NON_NEGATIVE_LONG -> MhUtil.findStatic(LOOKUP, "nonNegative", - MethodType.methodType(boolean.class, long.class)); - case SUCCESS_LONG -> MhUtil.findStatic(LOOKUP, "success", - MethodType.methodType(long.class, long.class, MemorySegment.class)); - case ERROR_LONG -> MhUtil.findStatic(LOOKUP, "error", - MethodType.methodType(long.class, MethodHandle.class, long.class, MemorySegment.class)); - case ACQUIRE_ARENA -> MhUtil.findStatic(LOOKUP, "acquireArena", - MethodType.methodType(Arena.class)); - case ALLOCATE -> MhUtil.findStatic(LOOKUP, "allocate", - MethodType.methodType(MemorySegment.class, Arena.class)); - case ARENA_CLOSE -> MhUtil.findVirtual(LOOKUP, Arena.class, "close", - MethodType.methodType(void.class)); - default -> throw new InternalError("Unknown index: " + index); - }; - } - -} diff --git a/src/java.base/share/classes/jdk/internal/foreign/SlicingAllocator.java b/src/java.base/share/classes/jdk/internal/foreign/SlicingAllocator.java index 6b1a071c2af0..3aec538885ca 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SlicingAllocator.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SlicingAllocator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -38,22 +38,6 @@ public SlicingAllocator(MemorySegment segment) { this.segment = segment; } - public long currentOffset() { - return sp; - } - - public void resetTo(long offset) { - if (offset < 0 || offset > sp) - throw new IllegalArgumentException(String.format("offset %d should be in [0, %d] ", offset, sp)); - this.sp = offset; - } - - public boolean canAllocate(long byteSize, long byteAlignment) { - long min = segment.address(); - long start = Utils.alignUp(min + sp, byteAlignment) - min; - return start + byteSize <= segment.byteSize(); - } - MemorySegment trySlice(long byteSize, long byteAlignment) { long min = segment.address(); long start = Utils.alignUp(min + sp, byteAlignment) - min; diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java index 37200598d5b0..5e4d667b4f68 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/SharedUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -22,11 +22,11 @@ * or visit www.oracle.com if you need additional information or have any * questions. */ + package jdk.internal.foreign.abi; import jdk.internal.access.JavaLangInvokeAccess; import jdk.internal.access.SharedSecrets; -import jdk.internal.foreign.BufferStack; import jdk.internal.foreign.CABI; import jdk.internal.foreign.abi.AbstractLinker.UpcallStubFactory; import jdk.internal.foreign.abi.aarch64.linux.LinuxAArch64Linker; @@ -390,15 +390,29 @@ static long pickChunkOffset(long chunkOffset, long byteWidth, int chunkWidth) { : chunkOffset; } - private static final int LINKER_STACK_SIZE = Integer.getInteger("jdk.internal.foreign.LINKER_STACK_SIZE", 256); - private static final BufferStack LINKER_STACK = BufferStack.of(LINKER_STACK_SIZE, 1); - @ForceInline - public static Arena newBoundedArena(long size) { - return LINKER_STACK.pushFrame(size, 8); + static Arena newBoundedArena(long size) { + return BoundedArena.of(size); + } + + private record BoundedArena(Arena delegate, SegmentAllocator allocator) implements Arena { + @ForceInline @Override + public MemorySegment allocate(long byteSize, long byteAlignment) { return allocator.allocate(byteSize, byteAlignment); } + @ForceInline @Override + public Scope scope() { return delegate.scope(); } + @ForceInline @Override + public void close() { delegate.close(); } + + @ForceInline + static Arena of(long size) { + final Arena arena = Arena.ofConfined(); + final SegmentAllocator allocator = SegmentAllocator.slicingAllocator(arena.allocate(size)); + return new BoundedArena(arena, allocator); + } + } - public static Arena newEmptyArena() { + static Arena newEmptyArena() { return new Arena() { final Arena arena = Arena.ofConfined(); diff --git a/src/java.base/share/classes/jdk/internal/util/SystemProps.java b/src/java.base/share/classes/jdk/internal/util/SystemProps.java index 5760f04831e0..73ab9e17a1d5 100644 --- a/src/java.base/share/classes/jdk/internal/util/SystemProps.java +++ b/src/java.base/share/classes/jdk/internal/util/SystemProps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -127,7 +127,6 @@ public static Map initProperties() { putIfAbsent(props, "sun.arch.data.model", raw.propDefault(Raw._sun_arch_data_model_NDX)); putIfAbsent(props, "sun.os.patch.level", raw.propDefault(Raw._sun_os_patch_level_NDX)); putIfAbsent(props, "sun.io.unicode.encoding", raw.propDefault(Raw._sun_io_unicode_encoding_NDX)); - putIfAbsent(props, "sun.cpu.isalist", raw.propDefault(Raw._sun_cpu_isalist_NDX)); putIfAbsent(props, "sun.cpu.endian", raw.propDefault(Raw._sun_cpu_endian_NDX)); /* Construct i18n related options */ @@ -249,8 +248,7 @@ public static class Raw { @Native private static final int _sun_arch_abi_NDX = 1 + _stdout_encoding_NDX; @Native private static final int _sun_arch_data_model_NDX = 1 + _sun_arch_abi_NDX; @Native private static final int _sun_cpu_endian_NDX = 1 + _sun_arch_data_model_NDX; - @Native private static final int _sun_cpu_isalist_NDX = 1 + _sun_cpu_endian_NDX; - @Native private static final int _sun_io_unicode_encoding_NDX = 1 + _sun_cpu_isalist_NDX; + @Native private static final int _sun_io_unicode_encoding_NDX = 1 + _sun_cpu_endian_NDX; @Native private static final int _sun_jnu_encoding_NDX = 1 + _sun_io_unicode_encoding_NDX; @Native private static final int _sun_os_patch_level_NDX = 1 + _sun_jnu_encoding_NDX; @Native private static final int _user_dir_NDX = 1 + _sun_os_patch_level_NDX; diff --git a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java index 09f6d7b1d756..54a3052b70fb 100644 --- a/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java +++ b/src/java.base/share/classes/sun/nio/ch/ChannelInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -223,18 +223,15 @@ public int available() throws IOException { @Override public synchronized long skip(long n) throws IOException { // special case where the channel is to a file - if (ch instanceof SeekableByteChannel sbc && - !(ch instanceof FileChannelImpl fci && isOther())) { + if (ch instanceof SeekableByteChannel sbc + && !(ch instanceof FileChannelImpl && isOther())) { long pos = sbc.position(); long newPos; if (n > 0) { - newPos = pos + n; - long size = sbc.size(); - if (newPos < 0 || newPos > size) { - newPos = size; - } + long remaining = Long.max(sbc.size() - pos, 0L); + newPos = pos + Long.min(n, remaining); } else { - newPos = Long.max(pos + n, 0); + newPos = Long.max(pos + n, 0L); } sbc.position(newPos); return newPos - pos; diff --git a/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java b/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java index 6d551462ce85..6077a671e92a 100644 --- a/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java +++ b/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -27,6 +27,7 @@ import java.nio.ByteBuffer; import jdk.internal.misc.TerminatingThreadLocal; +import jdk.internal.vm.ContinuationSupport; /** * Manipulates a native array of iovec structs on Solaris: @@ -96,27 +97,37 @@ private IOVecWrapper(int size) { } static IOVecWrapper get(int size) { - IOVecWrapper[] cache = IOV_CACHE.get(); - IOVecWrapper wrapper = cache[0]; - if (wrapper != null) { - cache[0] = null; - if (wrapper.size < size) { - // not big enough; eagerly release memory - wrapper.vecArray.free(); - wrapper = null; + ContinuationSupport.pinIfSupported(); + try { + IOVecWrapper[] cache = IOV_CACHE.get(); + IOVecWrapper wrapper = cache[0]; + if (wrapper != null) { + cache[0] = null; + if (wrapper.size < size) { + // not big enough; eagerly release memory + wrapper.vecArray.free(); + wrapper = null; + } } + return (wrapper != null) ? wrapper : new IOVecWrapper(size); + } finally { + ContinuationSupport.unpinIfSupported(); } - return (wrapper != null) ? wrapper : new IOVecWrapper(size); } void release() { - IOVecWrapper[] cache = IOV_CACHE.get(); - IOVecWrapper wrapper = cache[0]; - if (wrapper == null) { - cache[0] = this; - } else { - // slot already used - vecArray.free(); + ContinuationSupport.pinIfSupported(); + try { + IOVecWrapper[] cache = IOV_CACHE.get(); + IOVecWrapper wrapper = cache[0]; + if (wrapper == null) { + cache[0] = this; + } else { + // slot already used + vecArray.free(); + } + } finally { + ContinuationSupport.unpinIfSupported(); } } diff --git a/src/java.base/share/classes/sun/nio/ch/Poller.java b/src/java.base/share/classes/sun/nio/ch/Poller.java index 9360bcc8327c..523630600716 100644 --- a/src/java.base/share/classes/sun/nio/ch/Poller.java +++ b/src/java.base/share/classes/sun/nio/ch/Poller.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, 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 @@ -36,6 +36,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.locks.LockSupport; import java.util.function.BooleanSupplier; import jdk.internal.access.JavaLangAccess; @@ -413,7 +414,11 @@ static void closeAll(Poller... pollers) { } /** - * SYSTEM_THREADS poller group. The read and write pollers are system-wide platform threads. + * SYSTEM_THREADS poller group. The read and write pollers are system-wide platform + * threads. To avoid a file descriptor being registered with both a read and write + * poller at the same time, the poller group can be configured to run without a + * write poller, in which case polling for POLLOUT does timed-parked to force the + * caller to retry write ops until they succeed (or fail). */ private static class SystemThreadsPollerGroup extends PollerGroup { // system-wide read and write pollers @@ -459,16 +464,29 @@ private Poller readPoller(int fdVal) { } private Poller writePoller(int fdVal) { - int index = provider().fdValToIndex(fdVal, writePollers.length); - return writePollers[index]; + if (writePollers.length > 0) { + int index = provider().fdValToIndex(fdVal, writePollers.length); + return writePollers[index]; + } else { + return null; + } } @Override void poll(int fdVal, int event, long nanos, BooleanSupplier isOpen) throws IOException { - Poller poller = (event == Net.POLLIN) - ? readPoller(fdVal) - : writePoller(fdVal); - poller.poll(fdVal, nanos, isOpen); + if (event == Net.POLLIN) { + readPoller(fdVal).poll(fdVal, nanos, isOpen); + } else { + Poller writePoller = writePoller(fdVal); + if (writePoller != null) { + writePoller.poll(fdVal, nanos, isOpen); + } else { + // random delay in [50ms, 120ms) + int max = ThreadLocalRandom.current().nextInt(50_000_000, 120_000_000); + long delay = (nanos > 0) ? Math.min(nanos, max) : max; + LockSupport.parkNanos(delay); + } + } } @Override diff --git a/src/java.base/share/classes/sun/nio/ch/Util.java b/src/java.base/share/classes/sun/nio/ch/Util.java index 24f1ee7d7690..5c9221058445 100644 --- a/src/java.base/share/classes/sun/nio/ch/Util.java +++ b/src/java.base/share/classes/sun/nio/ch/Util.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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,6 +40,7 @@ import jdk.internal.access.SharedSecrets; import jdk.internal.misc.TerminatingThreadLocal; import jdk.internal.misc.Unsafe; +import jdk.internal.vm.ContinuationSupport; public class Util { @@ -222,55 +223,64 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { // If a buffer of this size is too large for the cache, there // should not be a buffer in the cache that is at least as // large. So we'll just create a new one. Also, we don't have - // to remove the buffer from the cache (as this method does - // below) given that we won't put the new buffer in the cache. - if (isBufferTooLarge(size)) { - long addr = unsafe.allocateMemory(size); - return NIO_ACCESS.newDirectByteBuffer(addr, size); - } - - BufferCache cache = bufferCache.get(); - ByteBuffer buf = cache.get(size); - if (buf != null) { - return buf; - } else { - // No suitable buffer in the cache so we need to allocate a new - // one. To avoid the cache growing then we remove the first - // buffer from the cache and free it. - if (!cache.isEmpty()) { - buf = cache.removeFirst(); - free(buf); + // to remove a buffer from the cache given that we won't put + // the new buffer in the cache. + if (!isBufferTooLarge(size)) { + // Try to get buffer from carrier thread local cache + ContinuationSupport.pinIfSupported(); + try { + BufferCache cache = bufferCache.get(); + ByteBuffer buf = cache.get(size); + if (buf != null) { + return buf; + } + if (!cache.isEmpty()) { + // Free buffer to avoid cache growing + ByteBuffer fromCache = cache.removeFirst(); + free(fromCache); + } + } finally { + ContinuationSupport.unpinIfSupported(); } - long addr = unsafe.allocateMemory(size); - return NIO_ACCESS.newDirectByteBuffer(addr, size); } + + // Allocate and return new buffer + long addr = unsafe.allocateMemory(size); + return NIO_ACCESS.newDirectByteBuffer(addr, size); } /** * Returns a temporary buffer of at least the given size and * aligned to the alignment */ - public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, - int alignment) { - if (isBufferTooLarge(size)) { - return getTemporaryDirectBuffer(size + alignment - 1) - .alignedSlice(alignment); - } - - BufferCache cache = bufferCache.get(); - ByteBuffer buf = cache.get(size); - if (buf != null) { - if (buf.alignmentOffset(0, alignment) == 0) { - return buf; - } - } else { - if (!cache.isEmpty()) { - buf = cache.removeFirst(); - free(buf); + public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, int alignment) { + assert alignment > 0 && (alignment & (alignment - 1)) == 0; + assert size >= 0 && size % alignment == 0; + + int allocationSize = size + alignment - 1; + if (!isBufferTooLarge(allocationSize)) { + // Try to get buffer from carrier thread local cache + ContinuationSupport.pinIfSupported(); + try { + BufferCache cache = bufferCache.get(); + ByteBuffer buf = cache.get(allocationSize); + if (buf != null) { + return buf.alignedSlice(alignment); + } + if (!cache.isEmpty()) { + // Free buffer to avoid cache growing + ByteBuffer fromCache = cache.removeFirst(); + free(fromCache); + } + } finally { + ContinuationSupport.unpinIfSupported(); } } - return getTemporaryDirectBuffer(size + alignment - 1) - .alignedSlice(alignment); + + // Allocate new buffer and return slice with the required alignment + long addr = unsafe.allocateMemory(allocationSize); + return NIO_ACCESS.newDirectByteBuffer(addr, allocationSize) + .alignedSlice(alignment); } /** @@ -296,6 +306,7 @@ private static ByteBuffer unwrapIfAlignedSlice(ByteBuffer buf) { */ static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { buf = unwrapIfAlignedSlice(buf); + assert buf != null; // If the buffer is too large for the cache we don't have to // check the cache. We'll just free it. @@ -304,11 +315,16 @@ static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { return; } - assert buf != null; - BufferCache cache = bufferCache.get(); - if (!cache.offerFirst(buf)) { - // cache is full - free(buf); + // Return buffer to carrier thread local cache if possible + ContinuationSupport.pinIfSupported(); + try { + BufferCache cache = bufferCache.get(); + if (!cache.offerFirst(buf)) { + // cache is full + free(buf); + } + } finally { + ContinuationSupport.unpinIfSupported(); } } @@ -320,6 +336,7 @@ static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { */ static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { buf = unwrapIfAlignedSlice(buf); + assert buf != null; // If the buffer is too large for the cache we don't have to // check the cache. We'll just free it. @@ -328,11 +345,16 @@ static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { return; } - assert buf != null; - BufferCache cache = bufferCache.get(); - if (!cache.offerLast(buf)) { - // cache is full - free(buf); + // Return buffer to carrier thread local cache if possible + ContinuationSupport.pinIfSupported(); + try { + BufferCache cache = bufferCache.get(); + if (!cache.offerLast(buf)) { + // cache is full + free(buf); + } + } finally { + ContinuationSupport.unpinIfSupported(); } } diff --git a/src/java.base/share/classes/sun/nio/fs/NativeBuffers.java b/src/java.base/share/classes/sun/nio/fs/NativeBuffers.java index 750da8c1a3db..925636aea06c 100644 --- a/src/java.base/share/classes/sun/nio/fs/NativeBuffers.java +++ b/src/java.base/share/classes/sun/nio/fs/NativeBuffers.java @@ -27,6 +27,7 @@ import jdk.internal.misc.TerminatingThreadLocal; import jdk.internal.misc.Unsafe; +import jdk.internal.vm.ContinuationSupport; /** * Factory for native buffers. @@ -70,18 +71,23 @@ static NativeBuffer allocNativeBuffer(int size) { * local cache. */ static NativeBuffer getNativeBufferFromCache(int size) { - // return from cache if possible - NativeBuffer[] buffers = threadLocal.get(); - if (buffers != null) { - for (int i=0; i= size) { - buffers[i] = null; - return buffer; + ContinuationSupport.pinIfSupported(); + try { + // return from cache if possible + NativeBuffer[] buffers = threadLocal.get(); + if (buffers != null) { + for (int i = 0; i < TEMP_BUF_POOL_SIZE; i++) { + NativeBuffer buffer = buffers[i]; + if (buffer != null && buffer.size() >= size) { + buffers[i] = null; + return buffer; + } } } + return null; + } finally { + ContinuationSupport.unpinIfSupported(); } - return null; } /** @@ -105,29 +111,34 @@ static NativeBuffer getNativeBuffer(int size) { * then the buffer goes into the cache; otherwise the memory is deallocated. */ static void releaseNativeBuffer(NativeBuffer buffer) { - // create cache if it doesn't exist - NativeBuffer[] buffers = threadLocal.get(); - if (buffers == null) { - buffers = new NativeBuffer[TEMP_BUF_POOL_SIZE]; - buffers[0] = buffer; - threadLocal.set(buffers); - return; - } - // Put it in an empty slot if such exists - for (int i=0; i getRequestedServerNames() { return Objects.requireNonNullElse(requestedServerNames, Collections.emptyList()); } + + NamedGroup getNegotiatedNamedGroup() { + for (SSLCredentials credentials : handshakeCredentials) { + if (credentials instanceof NamedGroupCredentials ngCredentials) { + return ngCredentials.getNamedGroup(); + } + } + + return null; + } } diff --git a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java index 924ad14451e4..094020602be4 100644 --- a/src/java.base/share/classes/sun/security/ssl/NamedGroup.java +++ b/src/java.base/share/classes/sun/security/ssl/NamedGroup.java @@ -33,8 +33,8 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; +import java.util.LinkedHashSet; import java.util.List; -import java.util.ArrayList; import java.util.Objects; import java.util.Set; import javax.crypto.KeyAgreement; @@ -433,33 +433,8 @@ static String nameOf(int id) { return "UNDEFINED-NAMED-GROUP(" + id + ")"; } - public static List namesOf(String[] namedGroups) { - if (namedGroups == null) { - return null; - } - - if (namedGroups.length == 0) { - return List.of(); - } - - List ngs = new ArrayList<>(namedGroups.length); - for (String ss : namedGroups) { - NamedGroup ng = NamedGroup.nameOf(ss); - if (ng == null || !ng.isAvailable) { - if (SSLLogger.isOn() && - SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE_VERBOSE)) { - SSLLogger.finest( - "Ignore the named group (" + ss - + "), unsupported or unavailable"); - } - - continue; - } - - ngs.add(ng); - } - - return Collections.unmodifiableList(ngs); + static String[] namesOf(List groups) { + return groups.stream().map(ng -> ng.name).toArray(String[]::new); } // Is there any supported group permitted by the constraints? @@ -919,6 +894,25 @@ static final class SupportedGroups { } } + // Returns all supported named groups for the specified protocols and + // cipher suites. Default named groups are returned first. + static List getSupportedGroups(List protocols, + List cipherSuites) { + + LinkedHashSet supportedGroups = new LinkedHashSet<>(); + supportedGroups.addAll(Arrays.asList(defaultGroups)); + supportedGroups.addAll(Arrays.asList(NamedGroup.values())); + + return supportedGroups.stream() + .filter(ng -> ng.isAvailable(protocols)) + .filter(ng -> ng.isSupported(cipherSuites)) + .filter(ng -> SSLConfiguration.enableFFDHE || + ng.spec != NamedGroupSpec.NAMED_GROUP_FFDHE) + .filter(ng -> ng.isPermitted( + SSLAlgorithmConstraints.DEFAULT)) + .toList(); + } + // Avoid the group lookup for default and customized groups. static NamedGroup[] getGroupsFromConfig(SSLConfiguration sslConfig) { if (sslConfig.namedGroups == defaultNames) { diff --git a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java index fdeb94bb4969..c65256da3ce9 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java @@ -293,6 +293,12 @@ StatusResponseManager getStatusResponseManager() { // Is the context for DTLS protocols? abstract boolean isDTLS(); + // Get supported Named Groups. + List getSupportedNamedGroups() { + return NamedGroup.SupportedGroups.getSupportedGroups( + getSupportedProtocolVersions(), getSupportedCipherSuites()); + } + // Get default protocols. List getDefaultProtocolVersions(boolean roleIsServer) { return roleIsServer ? getServerDefaultProtocolVersions() diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java index 5052f9bc9f4e..77ea04e4ad43 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -1082,6 +1082,11 @@ public void setHandshakeApplicationProtocolSelector( } } + @Override + public String [] getSupportedNamedGroups() { + return NamedGroup.namesOf(sslContext.getSupportedNamedGroups()); + } + @Override public boolean useDelegatedTask() { return true; diff --git a/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java index 1b959f982b9e..9f7e5884ce39 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLServerSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, 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 @@ -264,6 +264,11 @@ public void setSSLParameters(SSLParameters params) { } } + @Override + public String [] getSupportedNamedGroups() { + return NamedGroup.namesOf(sslContext.getSupportedNamedGroups()); + } + @Override public Socket accept() throws IOException { SSLSocketImpl s = new SSLSocketImpl(sslContext, sslConfig); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java index 45882a79fd70..bd83d0703fce 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java @@ -102,6 +102,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { private final Collection localSupportedSignAlgs; private Collection peerSupportedSignAlgs; //for certificate private boolean useDefaultPeerSignAlgs = false; + private NamedGroup namedGroup; private List statusResponses; private SecretKey exporterMasterSecret; // TLSv1.3+ exporter info private RandomCookie clientRandom; // TLSv1.2- exporter info @@ -1413,6 +1414,15 @@ Collection getPeerSupportedSignatureSchemes() { return peerSupportedSignAlgs; } + @Override + public String getNamedGroup() { + return namedGroup == null ? null : namedGroup.name; + } + + void setNamedGroup(NamedGroup namedGroup) { + this.namedGroup = namedGroup; + } + /** * Obtains a List containing all {@link SNIServerName}s * of the requested Server Name Indication (SNI) extension. diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index cef2f43526a8..8ab583a2e386 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1415,6 +1415,11 @@ public void setHandshakeApplicationProtocolSelector( } } + @Override + public String [] getSupportedNamedGroups() { + return NamedGroup.namesOf(sslContext.getSupportedNamedGroups()); + } + /** * Read the initial handshake records. */ diff --git a/src/java.base/share/data/cacerts/certumec384ca b/src/java.base/share/data/cacerts/certumec384ca new file mode 100644 index 000000000000..47a276e915ad --- /dev/null +++ b/src/java.base/share/data/cacerts/certumec384ca @@ -0,0 +1,22 @@ +Owner: CN=Certum EC-384 CA, OU=Certum Certification Authority, O=Asseco Data Systems S.A., C=PL +Issuer: CN=Certum EC-384 CA, OU=Certum Certification Authority, O=Asseco Data Systems S.A., C=PL +Serial number: 788f275c81125220a504d02dddba73f4 +Valid from: Mon Mar 26 07:24:54 GMT 2018 until: Thu Mar 26 07:24:54 GMT 2043 +Signature algorithm name: SHA384withECDSA +Subject Public Key Algorithm: 384-bit EC (secp384r1) key +Version: 3 +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw +CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw +JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT +EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 +WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT +LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX +BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE +KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm +Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 +EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J +UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn +nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/cacerts/certumtrustedrootca b/src/java.base/share/data/cacerts/certumtrustedrootca new file mode 100644 index 000000000000..fb1dc35f62cd --- /dev/null +++ b/src/java.base/share/data/cacerts/certumtrustedrootca @@ -0,0 +1,40 @@ +Owner: CN=Certum Trusted Root CA, OU=Certum Certification Authority, O=Asseco Data Systems S.A., C=PL +Issuer: CN=Certum Trusted Root CA, OU=Certum Certification Authority, O=Asseco Data Systems S.A., C=PL +Serial number: 1ebf5950b8c980374c06f7eb554fb5ed +Valid from: Fri Mar 16 12:10:13 GMT 2018 until: Mon Mar 16 12:10:13 GMT 2043 +Signature algorithm name: SHA512withRSA +Subject Public Key Algorithm: 4096-bit RSA key +Version: 3 +-----BEGIN CERTIFICATE----- +MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6 +MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu +MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV +BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw +MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg +U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo +b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ +n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q +p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq +NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF +8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3 +HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa +mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi +7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF +ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P +qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ +v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6 +Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1 +vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD +ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4 +WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo +zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR +5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ +GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf +5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq +0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D +P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM +qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP +0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf +E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb +-----END CERTIFICATE----- diff --git a/src/java.base/share/data/tzdata/tzmappings.override b/src/java.base/share/data/tzdata/tzmappings.override index 8466e3585c3c..0ccc52caf9a6 100644 --- a/src/java.base/share/data/tzdata/tzmappings.override +++ b/src/java.base/share/data/tzdata/tzmappings.override @@ -38,3 +38,7 @@ British Columbia Standard Time:001:America/Vancouver: # tz2026c: Alberta # https://techcommunity.microsoft.com/blog/dstblog/interim-guidance-for-alberta-time-zone-changes-2026/4545015 Alberta Standard Time:001:America/Edmonton: + +# tz2026e: Manitoba +# https://techcommunity.microsoft.com/blog/dstblog/interim-guidance-for-manitoba-permanent-dst-2026/4562488 +Manitoba Standard Time:001:America/Winnipeg: diff --git a/src/java.base/share/native/libjava/System.c b/src/java.base/share/native/libjava/System.c index 725c1e302272..19f7922af559 100644 --- a/src/java.base/share/native/libjava/System.c +++ b/src/java.base/share/native/libjava/System.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2026, 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 @@ -161,7 +161,6 @@ Java_jdk_internal_util_SystemProps_00024Raw_platformProperties(JNIEnv *env, jcla /* unicode_encoding specifies the default endianness */ PUTPROP(propArray, _sun_io_unicode_encoding_NDX, sprops->unicode_encoding); PUTPROP(propArray, _sun_cpu_endian_NDX, sprops->cpu_endian); - PUTPROP(propArray, _sun_cpu_isalist_NDX, sprops->cpu_isalist); #ifdef MACOSX /* Proxy setting properties */ diff --git a/src/java.base/share/native/libjava/java_props.h b/src/java.base/share/native/libjava/java_props.h index 774a7435e547..2b444ad4ec79 100644 --- a/src/java.base/share/native/libjava/java_props.h +++ b/src/java.base/share/native/libjava/java_props.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -72,8 +72,6 @@ typedef struct { char *unicode_encoding; /* The default endianness of unicode i.e. UnicodeBig or UnicodeLittle */ - const char *cpu_isalist; /* list of supported instruction sets */ - char *cpu_endian; /* endianness of platform */ char *data_model; /* 32 or 64 bit data model */ diff --git a/src/java.base/unix/native/libjava/java_props_md.c b/src/java.base/unix/native/libjava/java_props_md.c index 1cbc3665ebc4..5f2a4ccf6283 100644 --- a/src/java.base/unix/native/libjava/java_props_md.c +++ b/src/java.base/unix/native/libjava/java_props_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -384,21 +384,6 @@ GetJavaProperties(JNIEnv *env) /* patches/service packs installed */ sprops.patch_level = NULL; // leave it undefined -#ifdef SI_ISALIST - /* supported instruction sets */ - { - char list[258]; - int ret = sysinfo(SI_ISALIST, list, sizeof(list)); - if (ret == 0) { - sprops.cpu_isalist = strdup(list); - } else { - sprops.cpu_isalist = NULL; - } - } -#else - sprops.cpu_isalist = NULL; -#endif - /* endianness of platform */ { unsigned int endianTest = 0xff000000; diff --git a/src/java.base/unix/native/libnet/Inet4AddressImpl.c b/src/java.base/unix/native/libnet/Inet4AddressImpl.c index e99dfd894119..0f8b49079854 100644 --- a/src/java.base/unix/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet4AddressImpl.c @@ -105,7 +105,6 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, // try once, with our static buffer memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET; NET_RESTARTABLE(error, getaddrinfo(hostname, NULL, &hints, &res), diff --git a/src/java.base/unix/native/libnet/Inet6AddressImpl.c b/src/java.base/unix/native/libnet/Inet6AddressImpl.c index e0963c8dc3eb..53440ffea6c1 100644 --- a/src/java.base/unix/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/unix/native/libnet/Inet6AddressImpl.c @@ -224,7 +224,6 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, // try once, with our static buffer memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; hints.ai_family = lookupCharacteristicsToAddressFamily(characteristics); NET_RESTARTABLE(error, getaddrinfo(hostname, NULL, &hints, &res), diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c index 5ed99f256d80..9cf50845bfd9 100644 --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -1593,7 +1593,7 @@ static int getMacAddress unsigned char *buf) { int size; - struct kinfo_ndd *nddp; + struct kinfo_ndd *nddp, *orig_nddp; void *end; size = getkerninfo(KINFO_NDD, 0, 0, 0); @@ -1621,18 +1621,20 @@ static int getMacAddress } end = (void *)nddp + size; + orig_nddp = nddp; + while ((void *)nddp < end) { if (!strcmp(nddp->ndd_alias, ifname) || !strcmp(nddp->ndd_name, ifname)) { bcopy(nddp->ndd_addr, buf, 6); - free(nddp); + free(orig_nddp); return 6; } else { nddp++; } } - free(nddp); + free(orig_nddp); return -1; } diff --git a/src/java.base/unix/native/libnet/net_util_md.c b/src/java.base/unix/native/libnet/net_util_md.c index 28afcefa399e..d629c697ffe2 100644 --- a/src/java.base/unix/native/libnet/net_util_md.c +++ b/src/java.base/unix/native/libnet/net_util_md.c @@ -413,8 +413,8 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg, int len) { -#ifdef MACOSX - /* macOS stores linger values as signed shorts in the kernel. */ +#ifdef _ALLBSD_SOURCE + /* macOS and BSD stores linger values as signed shorts in the kernel. */ if (level == SOL_SOCKET && opt == SO_LINGER) { struct linger* to_cast = (struct linger*)arg; if (to_cast->l_linger > 32767) { diff --git a/src/java.base/windows/classes/sun/nio/ch/DefaultPollerProvider.java b/src/java.base/windows/classes/sun/nio/ch/DefaultPollerProvider.java index d1af62fbd737..8f3339227f00 100644 --- a/src/java.base/windows/classes/sun/nio/ch/DefaultPollerProvider.java +++ b/src/java.base/windows/classes/sun/nio/ch/DefaultPollerProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, 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 @@ -47,6 +47,13 @@ int defaultReadPollers() { return Math.max(Integer.highestOneBit(ncpus / 8), 1); } + @Override + int defaultWritePollers() { + // No write pollers to ensure at most one AFD_POLL outstanding per socket + // (https://github.com/piscisaureus/wepoll/issues/35) + return 0; + } + @Override int fdValToIndex(int fdVal, int toIndex) { return (fdVal >> 2) & (toIndex - 1); diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c index 6504891af343..7847b1e78a28 100644 --- a/src/java.base/windows/native/libjava/java_props_md.c +++ b/src/java.base/windows/native/libjava/java_props_md.c @@ -40,10 +40,6 @@ #include "locale_str.h" #include "java_props.h" -#ifndef PROCESSOR_ARCHITECTURE_AMD64 -#define PROCESSOR_ARCHITECTURE_AMD64 9 -#endif - typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); static BOOL SetupI18nProps(LCID lcid, char** language, char** script, char** country, char** variant); @@ -227,36 +223,6 @@ getHomeFromShell32() return u_path; } -static BOOL -haveMMX(void) -{ - return IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE); -} - -static const char * -cpu_isalist(void) -{ - SYSTEM_INFO info; - GetSystemInfo(&info); - switch (info.wProcessorArchitecture) { -#ifdef PROCESSOR_ARCHITECTURE_AMD64 - case PROCESSOR_ARCHITECTURE_AMD64: return "amd64"; -#endif - case PROCESSOR_ARCHITECTURE_INTEL: - switch (info.wProcessorLevel) { - case 6: return haveMMX() - ? "pentium_pro+mmx pentium_pro pentium+mmx pentium i486 i386 i86" - : "pentium_pro pentium i486 i386 i86"; - case 5: return haveMMX() - ? "pentium+mmx pentium i486 i386 i86" - : "pentium i486 i386 i86"; - case 4: return "i486 i386 i86"; - case 3: return "i386 i86"; - } - } - return NULL; -} - static BOOL SetupI18nProps(LCID lcid, char** language, char** script, char** country, char** variant) { @@ -517,9 +483,6 @@ GetJavaProperties(JNIEnv* env) } } - /* CPU ISA list */ - sprops.cpu_isalist = cpu_isalist(); - /* * User name * We try to avoid calling GetUserName as it turns out to diff --git a/src/java.base/windows/native/libnet/DefaultProxySelector.c b/src/java.base/windows/native/libnet/DefaultProxySelector.c index 06bc70114f33..56bae4386d0c 100644 --- a/src/java.base/windows/native/libnet/DefaultProxySelector.c +++ b/src/java.base/windows/native/libnet/DefaultProxySelector.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, 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 @@ -65,6 +65,8 @@ Java_sun_net_spi_DefaultProxySelector_init(JNIEnv *env, jclass clazz) { } if (!initJavaClass(env)) { + WinHttpCloseHandle(session); + session = NULL; return JNI_FALSE; } @@ -330,20 +332,24 @@ Java_sun_net_spi_DefaultProxySelector_getSystemProxies(JNIEnv *env, jhost = (*env)->NewString(env, current->host, (jsize)wcslen(current->host)); if (jhost == NULL || (*env)->ExceptionCheck(env)) { proxy_array = NULL; + goto noproxy; } isa = (*env)->CallStaticObjectMethod(env, isaddr_class, isaddr_createUnresolvedID, jhost, current->port); if (isa == NULL || (*env)->ExceptionCheck(env)) { proxy_array = NULL; + goto noproxy; } proxy = (*env)->NewObject(env, proxy_class, proxy_ctrID, type_proxy, isa); if (proxy == NULL || (*env)->ExceptionCheck(env)) { proxy_array = NULL; + goto noproxy; } (*env)->SetObjectArrayElement(env, proxy_array, index, proxy); if ((*env)->ExceptionCheck(env)) { proxy_array = NULL; + goto noproxy; } index++; } diff --git a/src/java.base/windows/native/libnet/Inet4AddressImpl.c b/src/java.base/windows/native/libnet/Inet4AddressImpl.c index 93210b0f6a51..91b307375006 100644 --- a/src/java.base/windows/native/libnet/Inet4AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet4AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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,6 +23,7 @@ * questions. */ #include +#include #include "net_util.h" @@ -81,7 +82,6 @@ Java_java_net_Inet4AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, // try once, with our static buffer memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; hints.ai_family = AF_INET; error = getaddrinfo(hostname, NULL, &hints, &res); @@ -327,6 +327,7 @@ ping4(JNIEnv *env, HANDLE hIcmpFile, SOCKETADDRESS *sa, // to hold at least one ICMP_ECHO_REPLY // structure + sizeof(SendData) // plus RequestSize bytes of data. + + sizeof(IO_STATUS_BLOCK) // plus space for an IO_STATUS_BLOCK (for IcmpSendEcho2Ex). + 8; // This buffer should also be large enough // to also hold 8 more bytes of data // (the size of an ICMP error message) diff --git a/src/java.base/windows/native/libnet/Inet6AddressImpl.c b/src/java.base/windows/native/libnet/Inet6AddressImpl.c index 6e5306164e19..812693299ba2 100644 --- a/src/java.base/windows/native/libnet/Inet6AddressImpl.c +++ b/src/java.base/windows/native/libnet/Inet6AddressImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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,6 +23,7 @@ * questions. */ #include +#include #include "net_util.h" @@ -76,7 +77,6 @@ Java_java_net_Inet6AddressImpl_lookupAllHostAddr(JNIEnv *env, jobject this, // try once, with our static buffer memset(&hints, 0, sizeof(hints)); - hints.ai_flags = AI_CANONNAME; hints.ai_family = lookupCharacteristicsToAddressFamily(characteristics); error = getaddrinfo(hostname, NULL, &hints, &res); @@ -400,7 +400,9 @@ ping6(JNIEnv *env, HANDLE hIcmpFile, SOCKETADDRESS *sa, IP_OPTION_INFORMATION ipInfo = {255, 0, 0, 0, NULL}; SOCKETADDRESS dftNetif; - ReplySize = sizeof(ICMPV6_ECHO_REPLY) + sizeof(SendData); + // According to MS docu: size of ICMPV6_ECHO_REPLY structure + RequestSize bytes of data + + // 8 more bytes of data (the size of an ICMP error message) + size of an IO_STATUS_BLOCK structure + ReplySize = sizeof(ICMPV6_ECHO_REPLY) + sizeof(SendData) + 8 + sizeof(IO_STATUS_BLOCK); ReplyBuffer = (VOID *)malloc(ReplySize); if (ReplyBuffer == NULL) { IcmpCloseHandle(hIcmpFile); diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDesktopPeer.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDesktopPeer.java index cc0e253f23b5..9e062c8197db 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDesktopPeer.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CDesktopPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, 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 @@ -39,7 +39,6 @@ import java.nio.file.Files; import java.nio.file.Path; - /** * Concrete implementation of the interface {@code DesktopPeer} for MacOS X * @@ -80,7 +79,7 @@ public void mail(URI uri) throws IOException { @Override public void browse(URI uri) throws IOException { - this.lsOpen(uri, BROWSE); + this.lsOpen(uri, isBrowseInsecureAllowed(uri) ? OPEN : BROWSE); } @Override diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/CDesktopPeer.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/CDesktopPeer.m index faacef5adea0..65a1d2bc2134 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/CDesktopPeer.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/CDesktopPeer.m @@ -42,16 +42,18 @@ NSURL *urlToOpen = [NSURL URLWithString:JavaStringToNSString(env, uri)]; NSURL *appURI = nil; + NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; - if (action == sun_lwawt_macosx_CDesktopPeer_BROWSE) { + if (action == sun_lwawt_macosx_CDesktopPeer_OPEN) { + // Open with the app associated with the URI scheme + appURI = [workspace URLForApplicationToOpenURL:urlToOpen]; + } else if (action == sun_lwawt_macosx_CDesktopPeer_BROWSE) { // To get the defaultBrowser NSURL *httpsURL = [NSURL URLWithString:@"https://"]; - NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; appURI = [workspace URLForApplicationToOpenURL:httpsURL]; } else if (action == sun_lwawt_macosx_CDesktopPeer_MAIL) { // To get the default mailer NSURL *mailtoURL = [NSURL URLWithString:@"mailto://"]; - NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; appURI = [workspace URLForApplicationToOpenURL:mailtoURL]; } diff --git a/src/java.desktop/share/classes/java/awt/peer/DesktopPeer.java b/src/java.desktop/share/classes/java/awt/peer/DesktopPeer.java index c1b13a4e8f3b..61b595c04a65 100644 --- a/src/java.desktop/share/classes/java/awt/peer/DesktopPeer.java +++ b/src/java.desktop/share/classes/java/awt/peer/DesktopPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, 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 @@ -38,6 +38,7 @@ import java.io.File; import java.io.IOException; import java.net.URI; +import java.util.Arrays; import javax.swing.JMenuBar; @@ -281,4 +282,25 @@ default boolean moveToTrash(File file) { return false; } + /** + * Returns whether or not Desktop.browse() will open URI in browser or + * in associated allowed app + * + * @param uri URI to be browsed + * @return whether or not associated app will be opened + */ + default boolean isBrowseInsecureAllowed(URI uri) { + String allowList = System.getProperty("awt.desktop.browse_insecure"); + String scheme = uri.getScheme(); + + // For http,https scheme URL should always open in browser + // For other schemes, it will depend on whether scheme is in allowList + + return scheme != null && !(scheme.equals("http") || scheme.equals("https")) + && allowList != null + && (allowList.equals("*") + || Arrays.stream(allowList.split(",")) + .map(String::trim) + .anyMatch(allowed -> allowed.equalsIgnoreCase(scheme))); + } } diff --git a/src/java.desktop/share/classes/sun/print/CustomMediaSizeName.java b/src/java.desktop/share/classes/sun/print/CustomMediaSizeName.java index d5173c181c44..9fcc3233778c 100644 --- a/src/java.desktop/share/classes/sun/print/CustomMediaSizeName.java +++ b/src/java.desktop/share/classes/sun/print/CustomMediaSizeName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -183,6 +183,7 @@ public Media[] getSuperEnumTable() { /** * Returns the string table for class CustomMediaSizeName. */ + @Override protected String[] getStringTable() { String[] nameTable = new String[customStringTable.size()]; return customStringTable.toArray(nameTable); @@ -191,6 +192,7 @@ protected String[] getStringTable() { /** * Returns the enumeration value table for class CustomMediaSizeName. */ + @Override protected EnumSyntax[] getEnumValueTable() { MediaSizeName[] enumTable = new MediaSizeName[customEnumTable.size()]; return customEnumTable.toArray(enumTable); @@ -227,6 +229,7 @@ public SizeNameChoiceItem(String name, String choice, float width, float length) this.length = length; } + @Override public boolean equals(Object object) { if (this == object) return true; if (object == null || getClass() != object.getClass()) return false; @@ -237,6 +240,7 @@ public boolean equals(Object object) { Float.compare(this.length, that.length) == 0; } + @Override public int hashCode() { return Objects.hash(name, choice, width, length); } diff --git a/src/java.desktop/share/classes/sun/print/CustomMediaTray.java b/src/java.desktop/share/classes/sun/print/CustomMediaTray.java index e1ce64106b1b..0c6653660045 100644 --- a/src/java.desktop/share/classes/sun/print/CustomMediaTray.java +++ b/src/java.desktop/share/classes/sun/print/CustomMediaTray.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -84,6 +84,7 @@ public Media[] getSuperEnumTable() { /** * Returns the string table for class CustomMediaTray. */ + @Override protected String[] getStringTable() { String[] nameTable = new String[customStringTable.size()]; return customStringTable.toArray(nameTable); @@ -92,6 +93,7 @@ protected String[] getStringTable() { /** * Returns the enumeration value table for class CustomMediaTray. */ + @Override protected EnumSyntax[] getEnumValueTable() { MediaTray[] enumTable = new MediaTray[customEnumTable.size()]; return customEnumTable.toArray(enumTable); @@ -117,6 +119,7 @@ public NameChoiceItem(String name, String choice) { this.choice = choice; } + @Override public boolean equals(Object object) { if (this == object) return true; if (object == null || getClass() != object.getClass()) return false; @@ -125,6 +128,7 @@ public boolean equals(Object object) { && Objects.equals(this.choice, that.choice); } + @Override public int hashCode() { return Objects.hash(name, choice); } diff --git a/src/java.desktop/share/classes/sun/print/ImagePrinter.java b/src/java.desktop/share/classes/sun/print/ImagePrinter.java index dd5f5639ab5e..41eead6087b8 100644 --- a/src/java.desktop/share/classes/sun/print/ImagePrinter.java +++ b/src/java.desktop/share/classes/sun/print/ImagePrinter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -52,6 +52,7 @@ class ImagePrinter implements Printable { } } + @Override public int print(Graphics g, PageFormat pf, int index) { if (index > 0 || image == null) { diff --git a/src/java.desktop/share/classes/sun/print/OpenBook.java b/src/java.desktop/share/classes/sun/print/OpenBook.java index 4ce61b454567..a86b98ec5b7e 100644 --- a/src/java.desktop/share/classes/sun/print/OpenBook.java +++ b/src/java.desktop/share/classes/sun/print/OpenBook.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2000, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -68,6 +68,7 @@ class OpenBook implements Pageable { /** * This object does not know the number of pages. */ + @Override public int getNumberOfPages(){ return UNKNOWN_NUMBER_OF_PAGES; } @@ -78,6 +79,7 @@ public int getNumberOfPages(){ * PageFormat is being requested. * @return The PageFormat describing the size and orientation */ + @Override public PageFormat getPageFormat(int pageIndex) { return mFormat; } @@ -89,6 +91,7 @@ public PageFormat getPageFormat(int pageIndex) { * Printable is being requested. * @return The Printable that will draw the page. */ + @Override public Printable getPrintable(int pageIndex) throws IndexOutOfBoundsException { diff --git a/src/java.desktop/share/classes/sun/print/PSPathGraphics.java b/src/java.desktop/share/classes/sun/print/PSPathGraphics.java index 293cdd7f10df..d06cb0cc4278 100644 --- a/src/java.desktop/share/classes/sun/print/PSPathGraphics.java +++ b/src/java.desktop/share/classes/sun/print/PSPathGraphics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -78,6 +78,7 @@ class PSPathGraphics extends PathGraphics { * this graphics context. * @since 1.0 */ + @Override public Graphics create() { return new PSPathGraphics((Graphics2D) getDelegate().create(), @@ -94,6 +95,7 @@ public Graphics create() { * so that we can generate PostScript in user space * rather than device space. */ + @Override public void fill(Shape s, Color color) { deviceFill(s.getPathIterator(new AffineTransform()), color); } @@ -110,6 +112,7 @@ public void fill(Shape s, Color color) { * @see java.awt.Graphics#drawChars * @since 1.0 */ + @Override public void drawString(String str, int x, int y) { drawString(str, (float) x, (float) y); } @@ -136,20 +139,24 @@ public void drawString(String str, int x, int y) { * @see #setComposite * @see #setClip */ + @Override public void drawString(String str, float x, float y) { drawString(str, x, y, getFont(), getFontRenderContext(), 0f); } + @Override protected boolean canDrawStringToWidth() { return true; } + @Override protected int platformFontCount(Font font, String str) { PSPrinterJob psPrinterJob = (PSPrinterJob) getPrinterJob(); return psPrinterJob.platformFontCount(font, str); } + @Override protected void drawString(String str, float x, float y, Font font, FontRenderContext frc, float w) { if (str.length() == 0) { @@ -276,6 +283,7 @@ protected void drawString(String str, float x, float y, * @param handlingTransparency if being recursively called to * print opaque region of transparent image */ + @Override protected boolean drawImageToPlatform(Image image, AffineTransform xform, Color bgcolor, int srcX, int srcY, @@ -636,6 +644,7 @@ && canDoRedraws()) { * */ + @Override public void redrawRegion(Rectangle2D region, double scaleX, double scaleY, Shape savedClip, AffineTransform savedTransform) @@ -736,6 +745,7 @@ public void redrawRegion(Rectangle2D region, double scaleX, double scaleY, * with the specified color. * The path is provided in current user space. */ + @Override protected void deviceFill(PathIterator pathIter, Color color) { PSPrinterJob psPrinterJob = (PSPrinterJob) getPrinterJob(); @@ -746,6 +756,7 @@ protected void deviceFill(PathIterator pathIter, Color color) { * Draw the bounding rectangle using path by calling draw() * function and passing a rectangle shape. */ + @Override protected void deviceFrameRect(int x, int y, int width, int height, Color color) { @@ -756,6 +767,7 @@ protected void deviceFrameRect(int x, int y, int width, int height, * Draw a line using path by calling draw() function and passing * a line shape. */ + @Override protected void deviceDrawLine(int xBegin, int yBegin, int xEnd, int yEnd, Color color) { @@ -765,6 +777,7 @@ protected void deviceDrawLine(int xBegin, int yBegin, /* * Fill the rectangle with the specified color by calling fill(). */ + @Override protected void deviceFillRect(int x, int y, int width, int height, Color color) { fill(new Rectangle2D.Float(x, y, width, height)); @@ -776,6 +789,7 @@ protected void deviceFillRect(int x, int y, int width, int height, * FIX: Rework PathGraphics so that this method is * not an abstract method there. */ + @Override protected void deviceClip(PathIterator pathIter) { } diff --git a/src/java.desktop/share/classes/sun/print/PSPrinterJob.java b/src/java.desktop/share/classes/sun/print/PSPrinterJob.java index 03fdb532b713..576b4ffda681 100644 --- a/src/java.desktop/share/classes/sun/print/PSPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/PSPrinterJob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -387,6 +387,7 @@ public PSPrinterJob() * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ + @Override public boolean printDialog() throws HeadlessException { if (GraphicsEnvironment.isHeadless()) { @@ -477,6 +478,7 @@ protected void setAttributes(PrintRequestAttributeSet attributes) * this method is called to mark the start of a * document. */ + @Override protected void startDoc() throws PrinterException { // A security check has been performed in the @@ -720,6 +722,7 @@ mNoJobSheet, getJobNameInt(), /** * Invoked if the application cancelled the printjob. */ + @Override protected void abortDoc() { if (mPSStream != null && mDestType != RasterPrinterJob.STREAM) { mPSStream.close(); @@ -734,6 +737,7 @@ protected void abortDoc() { * this method is called after that last page * has been imaged. */ + @Override protected void endDoc() throws PrinterException { if (mPSStream != null) { mPSStream.println(EOF_COMMENT); @@ -778,6 +782,7 @@ private String getCoordPrep() { * The RasterPrintJob super class calls this method * at the start of each page. */ + @Override protected void startPage(PageFormat pageFormat, Printable painter, int index, boolean paperChanged) throws PrinterException @@ -828,6 +833,7 @@ protected void startPage(PageFormat pageFormat, Printable painter, * The RasterPrintJob super class calls this method * at the end of each page. */ + @Override protected void endPage(PageFormat format, Printable painter, int index) throws PrinterException @@ -934,6 +940,7 @@ protected void drawImageBGR(byte[] bgrData, * specified by the caller. Currently the data * is 24 bits per pixel in BGR format. */ + @Override protected void printBand(byte[] bgrData, int x, int y, int width, int height) throws PrinterException @@ -999,6 +1006,7 @@ protected void printBand(byte[] bgrData, int x, int y, * causes the print job to be rasterized. */ + @Override protected Graphics2D createPathGraphics(PeekGraphics peekGraphics, PrinterJob printerJob, Printable painter, @@ -1433,6 +1441,7 @@ protected float getPenY() { * Return the x resolution of the coordinates * to be rendered. */ + @Override protected double getXRes() { return xres; } @@ -1440,6 +1449,7 @@ protected double getXRes() { * Return the y resolution of the coordinates * to be rendered. */ + @Override protected double getYRes() { return yres; } @@ -1447,6 +1457,7 @@ protected double getYRes() { /** * Set the resolution at which to print. */ + @Override protected void setXYRes(double x, double y) { xres = x; yres = y; @@ -1456,6 +1467,7 @@ protected void setXYRes(double x, double y) { * For PostScript the origin is in the upper-left of the * paper not at the imageable area corner. */ + @Override protected double getPhysicalPrintableX(Paper p) { return 0; @@ -1465,22 +1477,27 @@ protected double getPhysicalPrintableX(Paper p) { * For PostScript the origin is in the upper-left of the * paper not at the imageable area corner. */ + @Override protected double getPhysicalPrintableY(Paper p) { return 0; } + @Override protected double getPhysicalPrintableWidth(Paper p) { return p.getImageableWidth(); } + @Override protected double getPhysicalPrintableHeight(Paper p) { return p.getImageableHeight(); } + @Override protected double getPhysicalPageWidth(Paper p) { return p.getWidth(); } + @Override protected double getPhysicalPageHeight(Paper p) { return p.getHeight(); } @@ -1491,10 +1508,12 @@ protected double getPhysicalPageHeight(Paper p) { * If the printer makes copies itself then this * method should return 1. */ + @Override protected int getNoncollatedCopies() { return 1; } + @Override protected int getCollatedCopies() { return 1; } diff --git a/src/java.desktop/share/classes/sun/print/PSStreamPrintJob.java b/src/java.desktop/share/classes/sun/print/PSStreamPrintJob.java index 0f420186f60e..8ace6e583120 100644 --- a/src/java.desktop/share/classes/sun/print/PSStreamPrintJob.java +++ b/src/java.desktop/share/classes/sun/print/PSStreamPrintJob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -93,10 +93,12 @@ public class PSStreamPrintJob implements CancelablePrintJob { this.service = service; } + @Override public PrintService getPrintService() { return service; } + @Override public PrintJobAttributeSet getAttributes() { synchronized (this) { if (jobAttrSet == null) { @@ -109,6 +111,7 @@ public PrintJobAttributeSet getAttributes() { } } + @Override public void addPrintJobListener(PrintJobListener listener) { synchronized (this) { if (listener == null) { @@ -121,6 +124,7 @@ public void addPrintJobListener(PrintJobListener listener) { } } + @Override public void removePrintJobListener(PrintJobListener listener) { synchronized (this) { if (listener == null || jobListeners == null ) { @@ -220,6 +224,7 @@ private void notifyEvent(int reason) { } } + @Override public void addPrintJobAttributeListener( PrintJobAttributeListener listener, PrintJobAttributeSet attributes) { @@ -239,6 +244,7 @@ public void addPrintJobAttributeListener( } } + @Override public void removePrintJobAttributeListener( PrintJobAttributeListener listener) { synchronized (this) { @@ -259,6 +265,7 @@ public void removePrintJobAttributeListener( } } + @Override public void print(Doc doc, PrintRequestAttributeSet attributes) throws PrintException { @@ -519,6 +526,7 @@ private void getAttributeValues(DocFlavor flavor) throws PrintException { } /* Cancel PrinterJob jobs that haven't yet completed. */ + @Override public void cancel() throws PrintException { synchronized (this) { if (!printing) { diff --git a/src/java.desktop/share/classes/sun/print/PSStreamPrintService.java b/src/java.desktop/share/classes/sun/print/PSStreamPrintService.java index e1594e051f5c..a65c967a7942 100644 --- a/src/java.desktop/share/classes/sun/print/PSStreamPrintService.java +++ b/src/java.desktop/share/classes/sun/print/PSStreamPrintService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -95,38 +95,46 @@ public PSStreamPrintService(OutputStream out) { super(out); } + @Override public String getOutputFormat() { return PSStreamPrinterFactory.psMimeType; } + @Override public DocFlavor[] getSupportedDocFlavors() { return PSStreamPrinterFactory.getFlavors(); } + @Override public DocPrintJob createPrintJob() { return new PSStreamPrintJob(this); } + @Override public boolean usesClass(Class c) { return (c == sun.print.PSPrinterJob.class); } + @Override public String getName() { return "Postscript output"; } + @Override public void addPrintServiceAttributeListener( PrintServiceAttributeListener listener) { return; } + @Override public void removePrintServiceAttributeListener( PrintServiceAttributeListener listener) { return; } + @Override public T getAttribute(Class category) { @@ -144,6 +152,7 @@ T getAttribute(Class category) return null; } } + @Override public PrintServiceAttributeSet getAttributes() { PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet(); attrs.add(ColorSupported.SUPPORTED); @@ -151,6 +160,7 @@ public PrintServiceAttributeSet getAttributes() { return AttributeSetUtilities.unmodifiableView(attrs); } + @Override public boolean isDocFlavorSupported(DocFlavor flavor) { DocFlavor [] flavors = getSupportedDocFlavors(); for (int f=0; f[] getSupportedAttributeCategories() { Class[] cats = new Class[suppAttrCats.length]; System.arraycopy(suppAttrCats, 0, cats, 0, cats.length); return cats; } + @Override public boolean isAttributeCategorySupported(Class category) { @@ -188,6 +200,7 @@ public Class[] getSupportedAttributeCategories() { } + @Override public Object getDefaultAttributeValue(Class category) { @@ -249,6 +262,7 @@ public Class[] getSupportedAttributeCategories() { } + @Override public Object getSupportedAttributeValues(Class category, DocFlavor flavor, @@ -401,6 +415,7 @@ private boolean isSupportedMedia(MediaSizeName msn) { return false; } + @Override public boolean isAttributeValueSupported(Attribute attr, DocFlavor flavor, AttributeSet attributes) { @@ -462,6 +477,7 @@ else if (attr.getCategory() == Copies.class) { return true; } + @Override public AttributeSet getUnsupportedAttributes(DocFlavor flavor, AttributeSet attributes) { @@ -496,10 +512,12 @@ public AttributeSet getUnsupportedAttributes(DocFlavor flavor, } } + @Override public ServiceUIFactory getServiceUIFactory() { return null; } + @Override public String toString() { return "PSStreamPrintService: " + getName(); } @@ -507,12 +525,14 @@ public String toString() { /* Stream services have an output stream which cannot be shared, * so two services are equal only if they are the same object. */ + @Override public boolean equals(Object obj) { return (obj == this || (obj instanceof PSStreamPrintService && ((PSStreamPrintService)obj).getName().equals(getName()))); } + @Override public int hashCode() { return this.getClass().hashCode()+getName().hashCode(); } diff --git a/src/java.desktop/share/classes/sun/print/PSStreamPrinterFactory.java b/src/java.desktop/share/classes/sun/print/PSStreamPrinterFactory.java index 3da8b03039aa..7b6b6201cf2c 100644 --- a/src/java.desktop/share/classes/sun/print/PSStreamPrinterFactory.java +++ b/src/java.desktop/share/classes/sun/print/PSStreamPrinterFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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,10 +49,12 @@ public class PSStreamPrinterFactory extends StreamPrintServiceFactory { DocFlavor.URL.PNG, }; + @Override public String getOutputFormat() { return psMimeType; } + @Override public DocFlavor[] getSupportedDocFlavors() { return getFlavors(); } @@ -63,6 +65,7 @@ static DocFlavor[] getFlavors() { return flavors; } + @Override public StreamPrintService getPrintService(OutputStream out) { return new PSStreamPrintService(out); } diff --git a/src/java.desktop/share/classes/sun/print/PageableDoc.java b/src/java.desktop/share/classes/sun/print/PageableDoc.java index ef829d5bfbb6..98b329abcd3d 100644 --- a/src/java.desktop/share/classes/sun/print/PageableDoc.java +++ b/src/java.desktop/share/classes/sun/print/PageableDoc.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -43,22 +43,27 @@ public PageableDoc(Pageable pageable) { this.pageable = pageable; } + @Override public DocFlavor getDocFlavor() { return DocFlavor.SERVICE_FORMATTED.PAGEABLE; } + @Override public DocAttributeSet getAttributes() { return new HashDocAttributeSet(); } + @Override public Object getPrintData() throws IOException { return pageable; } + @Override public Reader getReaderForText() throws IOException { return null; } + @Override public InputStream getStreamForBytes() throws IOException { return null; } diff --git a/src/java.desktop/share/classes/sun/print/PathGraphics.java b/src/java.desktop/share/classes/sun/print/PathGraphics.java index 5c4c34748eec..b89b7e8fc70d 100644 --- a/src/java.desktop/share/classes/sun/print/PathGraphics.java +++ b/src/java.desktop/share/classes/sun/print/PathGraphics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -153,6 +153,7 @@ public abstract void redrawRegion(Rectangle2D region, * @param x2 the second point's x coordinate. * @param y2 the second point's y coordinate. */ + @Override public void drawLine(int x1, int y1, int x2, int y2) { Paint paint = getPaint(); @@ -187,6 +188,7 @@ public void drawLine(int x1, int y1, int x2, int y2) { * @see java.awt.Graphics#fillRect * @see java.awt.Graphics#clearRect */ + @Override public void drawRect(int x, int y, int width, int height) { Paint paint = getPaint(); @@ -224,6 +226,7 @@ public void drawRect(int x, int y, int width, int height) { * @see java.awt.Graphics#clearRect * @see java.awt.Graphics#drawRect */ + @Override public void fillRect(int x, int y, int width, int height){ Paint paint = getPaint(); @@ -260,6 +263,7 @@ public void fillRect(int x, int y, int width, int height){ * @see java.awt.Graphics#setPaintMode * @see java.awt.Graphics#setXORMode(java.awt.Color) */ + @Override public void clearRect(int x, int y, int width, int height) { fill(new Rectangle2D.Float(x, y, width, height), getBackground()); @@ -281,6 +285,7 @@ public void clearRect(int x, int y, int width, int height) { * at the four corners. * @see java.awt.Graphics#fillRoundRect */ + @Override public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { @@ -306,6 +311,7 @@ public void drawRoundRect(int x, int y, int width, int height, * of the arc at the four corners. * @see java.awt.Graphics#drawRoundRect */ + @Override public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { @@ -332,6 +338,7 @@ public void fillRoundRect(int x, int y, int width, int height, * @see java.awt.Graphics#fillOval * @since 1.0 */ + @Override public void drawOval(int x, int y, int width, int height) { draw(new Ellipse2D.Float(x, y, width, height)); } @@ -347,6 +354,7 @@ public void drawOval(int x, int y, int width, int height) { * @param height the height of the oval to be filled. * @see java.awt.Graphics#drawOval */ + @Override public void fillOval(int x, int y, int width, int height){ fill(new Ellipse2D.Float(x, y, width, height)); @@ -389,6 +397,7 @@ public void fillOval(int x, int y, int width, int height){ * relative to the start angle. * @see java.awt.Graphics#fillArc */ + @Override public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { draw(new Arc2D.Float(x, y, width, height, @@ -433,6 +442,7 @@ public void drawArc(int x, int y, int width, int height, * relative to the start angle. * @see java.awt.Graphics#drawArc */ + @Override public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { @@ -453,6 +463,7 @@ public void fillArc(int x, int y, int width, int height, * @see java.awt.Graphics#drawPolygon(int[], int[], int) * @since 1.1 */ + @Override public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { @@ -489,6 +500,7 @@ public void drawPolyline(int[] xPoints, int[] yPoints, * @see java.awt.Graphics#fillPolygon * @see java.awt.Graphics#drawPolyline */ + @Override public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { @@ -502,6 +514,7 @@ public void drawPolygon(int[] xPoints, int[] yPoints, * @see java.awt.Graphics#fillPolygon * @see java.awt.Graphics#drawPolyline */ + @Override public void drawPolygon(Polygon p) { draw(p); } @@ -526,6 +539,7 @@ public void drawPolygon(Polygon p) { * @param nPoints the total number of points. * @see java.awt.Graphics#drawPolygon(int[], int[], int) */ + @Override public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { @@ -542,6 +556,7 @@ public void fillPolygon(int[] xPoints, int[] yPoints, * @param p the polygon to fill. * @see java.awt.Graphics#drawPolygon(int[], int[], int) */ + @Override public void fillPolygon(Polygon p) { fill(p); @@ -559,10 +574,12 @@ public void fillPolygon(Polygon p) { * @see java.awt.Graphics#drawChars * @since 1.0 */ + @Override public void drawString(String str, int x, int y) { drawString(str, (float) x, (float) y); } + @Override public void drawString(String str, float x, float y) { if (str.length() == 0) { return; @@ -593,10 +610,12 @@ protected void drawString(String str, float x, float y, * @see java.awt.Graphics#drawBytes * @see java.awt.Graphics#drawChars */ + @Override public void drawString(AttributedCharacterIterator iterator, int x, int y) { drawString(iterator, (float) x, (float) y); } + @Override public void drawString(AttributedCharacterIterator iterator, float x, float y) { if (iterator == null) { @@ -623,6 +642,7 @@ public void drawString(AttributedCharacterIterator iterator, * @see #clip * @see #setClip */ + @Override public void drawGlyphVector(GlyphVector g, float x, float y) { @@ -1055,6 +1075,7 @@ private static char[] getGlyphToCharMapForFont(Font2D font2D) { * @see #setClip * @see #setComposite */ + @Override public void draw(Shape s) { fill(getStroke().createStrokedShape(s)); @@ -1072,6 +1093,7 @@ public void draw(Shape s) { * @see #clip * @see #setClip */ + @Override public void fill(Shape s) { Paint paint = getPaint(); @@ -1411,6 +1433,7 @@ protected boolean drawBitmaskImage(BufferedImage bufferedImage, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, ImageObserver observer) { @@ -1451,6 +1474,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { @@ -1495,6 +1519,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { @@ -1556,6 +1581,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, @@ -1628,6 +1654,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.1 */ + @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, @@ -1693,6 +1720,7 @@ public boolean drawImage(Image img, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.1 */ + @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, @@ -1802,6 +1830,7 @@ public boolean drawImage(Image img, * @see #clip * @see #setClip */ + @Override public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { @@ -1842,6 +1871,7 @@ public boolean drawImage(Image img, * @see #clip * @see #setClip */ + @Override public void drawImage(BufferedImage img, BufferedImageOp op, int x, @@ -1886,6 +1916,7 @@ public void drawImage(BufferedImage img, * @see #clip * @see #setClip */ + @Override public void drawRenderedImage(RenderedImage img, AffineTransform xform) { diff --git a/src/java.desktop/share/classes/sun/print/PeekGraphics.java b/src/java.desktop/share/classes/sun/print/PeekGraphics.java index da6f12331d20..2c1ef65b41bf 100644 --- a/src/java.desktop/share/classes/sun/print/PeekGraphics.java +++ b/src/java.desktop/share/classes/sun/print/PeekGraphics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -123,6 +123,7 @@ public void setDelegate(Graphics2D graphics) { mGraphics = graphics; } + @Override public PrinterJob getPrinterJob() { return mPrinterJob; } @@ -153,6 +154,7 @@ public Spans getDrawingArea() { /** * Returns the device configuration associated with this Graphics2D. */ + @Override public GraphicsConfiguration getDeviceConfiguration() { return ((RasterPrinterJob)mPrinterJob).getPrinterGraphicsConfig(); } @@ -166,6 +168,7 @@ public GraphicsConfiguration getDeviceConfiguration() { * this graphics context. * @since 1.0 */ + @Override public Graphics create() { PeekGraphics newGraphics = null; @@ -196,6 +199,7 @@ public Graphics create() { * @param y the y coordinate. * @since 1.0 */ + @Override public void translate(int x, int y) { mGraphics.translate(x, y); } @@ -211,6 +215,7 @@ public void translate(int x, int y) { * [ 0 0 1 ] * */ + @Override public void translate(double tx, double ty) { mGraphics.translate(tx, ty); } @@ -229,6 +234,7 @@ public void translate(double tx, double ty) { * x axis toward the positive y axis. * @param theta The angle of rotation in radians. */ + @Override public void rotate(double theta) { mGraphics.rotate(theta); } @@ -248,6 +254,7 @@ public void rotate(double theta) { * @param x The x coordinate of the origin of the rotation * @param y The x coordinate of the origin of the rotation */ + @Override public void rotate(double theta, double x, double y) { mGraphics.rotate(theta, x, y); } @@ -263,6 +270,7 @@ public void rotate(double theta, double x, double y) { * [ 0 0 1 ] * */ + @Override public void scale(double sx, double sy) { mGraphics.scale(sx, sy); } @@ -282,6 +290,7 @@ public void scale(double sx, double sy) { * @param shy The factor by which coordinates are shifted towards the * positive Y axis direction according to their X coordinate */ + @Override public void shear(double shx, double shy) { mGraphics.shear(shx, shy); } @@ -293,6 +302,7 @@ public void shear(double shx, double shy) { * @see java.awt.Graphics#setColor * @since 1.0 */ + @Override public Color getColor() { return mGraphics.getColor(); } @@ -306,6 +316,7 @@ public Color getColor() { * @see java.awt.Graphics#getColor * @since 1.0 */ + @Override public void setColor(Color c) { mGraphics.setColor(c); } @@ -318,6 +329,7 @@ public void setColor(Color c) { * overwrite the destination with the current color. * @since 1.0 */ + @Override public void setPaintMode() { mGraphics.setPaintMode(); } @@ -338,6 +350,7 @@ public void setPaintMode() { * @param c1 the XOR alternation color * @since 1.0 */ + @Override public void setXORMode(Color c1) { mGraphics.setXORMode(c1); } @@ -349,6 +362,7 @@ public void setXORMode(Color c1) { * @see java.awt.Graphics#setFont * @since 1.0 */ + @Override public Font getFont() { return mGraphics.getFont(); } @@ -364,6 +378,7 @@ public Font getFont() { * @see java.awt.Graphics#drawBytes(byte[], int, int, int, int) * @since 1.0 */ + @Override public void setFont(Font font) { mGraphics.setFont(font); } @@ -377,6 +392,7 @@ public void setFont(Font font) { * @see java.awt.Graphics#getFontMetrics() * @since 1.0 */ + @Override public FontMetrics getFontMetrics(Font f) { return mGraphics.getFontMetrics(f); } @@ -385,6 +401,7 @@ public FontMetrics getFontMetrics(Font f) { * Get the rendering context of the font * within this Graphics2D context. */ + @Override public FontRenderContext getFontRenderContext() { return mGraphics.getFontRenderContext(); } @@ -400,6 +417,7 @@ public FontRenderContext getFontRenderContext() { * @see java.awt.Graphics#setClip(Shape) * @since 1.1 */ + @Override public Rectangle getClipBounds() { return mGraphics.getClipBounds(); } @@ -419,6 +437,7 @@ public Rectangle getClipBounds() { * @see #setClip(int, int, int, int) * @see #setClip(Shape) */ + @Override public void clipRect(int x, int y, int width, int height) { mGraphics.clipRect(x, y, width, height); } @@ -436,6 +455,7 @@ public void clipRect(int x, int y, int width, int height) { * @see java.awt.Graphics#setClip(Shape) * @since 1.1 */ + @Override public void setClip(int x, int y, int width, int height) { mGraphics.setClip(x, y, width, height); } @@ -450,6 +470,7 @@ public void setClip(int x, int y, int width, int height) { * @see java.awt.Graphics#setClip(Shape) * @since 1.1 */ + @Override public Shape getClip() { return mGraphics.getClip(); } @@ -468,6 +489,7 @@ public Shape getClip() { * @see java.awt.Graphics#setClip(int, int, int, int) * @since 1.1 */ + @Override public void setClip(Shape clip) { mGraphics.setClip(clip); } @@ -493,6 +515,7 @@ public void setClip(Shape clip) { * @param dy the vertical distance to copy the pixels. * @since 1.0 */ + @Override public void copyArea(int x, int y, int width, int height, int dx, int dy) { // This method is not supported for printing so we do nothing here. @@ -508,6 +531,7 @@ public void copyArea(int x, int y, int width, int height, * @param y2 the second point's y coordinate. * @since 1.0 */ + @Override public void drawLine(int x1, int y1, int x2, int y2) { addStrokeShape(new Line2D.Float(x1, y1, x2, y2)); mPrintMetrics.draw(this); @@ -535,6 +559,7 @@ public void drawLine(int x1, int y1, int x2, int y2) { * @see java.awt.Graphics#clearRect * @since 1.0 */ + @Override public void fillRect(int x, int y, int width, int height) { addDrawingRect(new Rectangle2D.Float(x, y, width, height)); @@ -562,6 +587,7 @@ public void fillRect(int x, int y, int width, int height) { * @see java.awt.Graphics#setXORMode(java.awt.Color) * @since 1.0 */ + @Override public void clearRect(int x, int y, int width, int height) { Rectangle2D.Float rect = new Rectangle2D.Float(x, y, width, height); addDrawingRect(rect); @@ -585,6 +611,7 @@ public void clearRect(int x, int y, int width, int height) { * @see java.awt.Graphics#fillRoundRect * @since 1.0 */ + @Override public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { addStrokeShape(new RoundRectangle2D.Float(x, y, width, height, arcWidth, arcHeight)); @@ -609,6 +636,7 @@ public void drawRoundRect(int x, int y, int width, int height, * @see java.awt.Graphics#drawRoundRect * @since 1.0 */ + @Override public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { Rectangle2D.Float rect = new Rectangle2D.Float(x, y,width, height); @@ -634,6 +662,7 @@ public void fillRoundRect(int x, int y, int width, int height, * @see java.awt.Graphics#fillOval * @since 1.0 */ + @Override public void drawOval(int x, int y, int width, int height) { addStrokeShape(new Rectangle2D.Float(x, y, width, height)); mPrintMetrics.draw(this); @@ -651,6 +680,7 @@ public void drawOval(int x, int y, int width, int height) { * @see java.awt.Graphics#drawOval * @since 1.0 */ + @Override public void fillOval(int x, int y, int width, int height) { Rectangle2D.Float rect = new Rectangle2D.Float(x, y, width, height); addDrawingRect(rect); @@ -689,6 +719,7 @@ public void fillOval(int x, int y, int width, int height) { * @see java.awt.Graphics#fillArc * @since 1.0 */ + @Override public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { addStrokeShape(new Rectangle2D.Float(x, y, width, height)); @@ -725,6 +756,7 @@ public void drawArc(int x, int y, int width, int height, * @see java.awt.Graphics#drawArc * @since 1.0 */ + @Override public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { Rectangle2D.Float rect = new Rectangle2D.Float(x, y,width, height); @@ -745,6 +777,7 @@ public void fillArc(int x, int y, int width, int height, * @see java.awt.Graphics#drawPolygon(int[], int[], int) * @since 1.1 */ + @Override public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { if (nPoints > 0) { @@ -780,6 +813,7 @@ public void drawPolyline(int[] xPoints, int[] yPoints, * @see java.awt.Graphics#drawPolyline * @since 1.0 */ + @Override public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { if (nPoints > 0) { @@ -811,6 +845,7 @@ public void drawPolygon(int[] xPoints, int[] yPoints, * @see java.awt.Graphics#drawPolygon(int[], int[], int) * @since 1.0 */ + @Override public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { if (nPoints > 0) { @@ -854,6 +889,7 @@ public void fillPolygon(int[] xPoints, int[] yPoints, * @see java.awt.Graphics#drawChars * @since 1.0 */ + @Override public void drawString(String str, int x, int y) { drawString(str, (float)x, (float)y); @@ -879,6 +915,7 @@ public void drawString(String str, int x, int y) { * @see #setComposite * @see #setClip */ + @Override public void drawString(AttributedCharacterIterator iterator, int x, int y) { @@ -905,6 +942,7 @@ public void drawString(AttributedCharacterIterator iterator, * @see #setComposite * @see #setClip */ + @Override public void drawString(AttributedCharacterIterator iterator, float x, float y) { if (iterator == null) { @@ -942,6 +980,7 @@ public void drawString(AttributedCharacterIterator iterator, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, ImageObserver observer) { @@ -995,6 +1034,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { @@ -1040,6 +1080,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { @@ -1099,6 +1140,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, @@ -1162,6 +1204,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.1 */ + @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, @@ -1236,6 +1279,7 @@ public boolean drawImage(Image img, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.1 */ + @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, @@ -1276,6 +1320,7 @@ public boolean drawImage(Image img, * @see #clip * @see #setClip */ + @Override public void drawRenderedImage(RenderedImage img, AffineTransform xform) { @@ -1288,6 +1333,7 @@ public void drawRenderedImage(RenderedImage img, } + @Override public void drawRenderableImage(RenderableImage img, AffineTransform xform) { @@ -1327,6 +1373,7 @@ public void drawRenderableImage(RenderableImage img, * @see java.awt.Graphics#create * @since 1.0 */ + @Override public void dispose() { mGraphics.dispose(); } @@ -1334,6 +1381,7 @@ public void dispose() { /** * Empty finalizer as no clean up needed here. */ + @Override @SuppressWarnings("removal") public void finalize() { } @@ -1354,6 +1402,7 @@ public void finalize() { * @see #setClip * @see #setComposite */ + @Override public void draw(Shape s) { addStrokeShape(s); mPrintMetrics.draw(this); @@ -1380,6 +1429,7 @@ public void draw(Shape s) { * @see #clip * @see #setClip */ + @Override public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { @@ -1427,6 +1477,7 @@ public boolean drawImage(Image img, * @see #clip * @see #setClip */ + @Override public void drawImage(BufferedImage img, BufferedImageOp op, int x, @@ -1456,6 +1507,7 @@ public void drawImage(BufferedImage img, * @see #clip * @see #setClip */ + @Override public void drawString(String str, float x, float y) { @@ -1485,6 +1537,7 @@ public void drawString(String str, * @see #clip * @see #setClip */ + @Override public void drawGlyphVector(GlyphVector g, float x, float y) { @@ -1507,6 +1560,7 @@ public void drawGlyphVector(GlyphVector g, * @see #clip * @see #setClip */ + @Override public void fill(Shape s) { addDrawingRect(s.getBounds()); mPrintMetrics.fill(this); @@ -1532,6 +1586,7 @@ public void fill(Shape s) { * @see #clip * @see #setClip */ + @Override public boolean hit(Rectangle rect, Shape s, boolean onStroke) { @@ -1549,6 +1604,7 @@ public boolean hit(Rectangle rect, * @see java.awt.Graphics#setPaintMode * @see java.awt.AlphaComposite */ + @Override public void setComposite(Composite comp) { mGraphics.setComposite(comp); } @@ -1562,6 +1618,7 @@ public void setComposite(Composite comp) { * @see java.awt.GradientPaint * @see java.awt.TexturePaint */ + @Override public void setPaint(Paint paint) { mGraphics.setPaint(paint); } @@ -1572,6 +1629,7 @@ public void setPaint(Paint paint) { * the rendering process. * @see BasicStroke */ + @Override public void setStroke(Stroke s) { mGraphics.setStroke(s); } @@ -1585,6 +1643,7 @@ public void setStroke(Stroke s) { * hint category. * @see RenderingHints */ + @Override public void setRenderingHint(Key hintCategory, Object hintValue) { mGraphics.setRenderingHint(hintCategory, hintValue); } @@ -1595,6 +1654,7 @@ public void setRenderingHint(Key hintCategory, Object hintValue) { * @return The preferences for rendering algorithms. * @see RenderingHints */ + @Override public Object getRenderingHint(Key hintCategory) { return mGraphics.getRenderingHint(hintCategory); } @@ -1606,6 +1666,7 @@ public Object getRenderingHint(Key hintCategory) { * @param hints The rendering hints to be set * @see RenderingHints */ + @Override public void setRenderingHints(Map hints) { mGraphics.setRenderingHints(hints); } @@ -1617,6 +1678,7 @@ public void setRenderingHints(Map hints) { * @param hints The rendering hints to be set * @see RenderingHints */ + @Override public void addRenderingHints(Map hints) { mGraphics.addRenderingHints(hints); } @@ -1627,6 +1689,7 @@ public void addRenderingHints(Map hints) { * overall time/quality trade-off in the rendering process. * @see RenderingHints */ + @Override public RenderingHints getRenderingHints() { return mGraphics.getRenderingHints(); } @@ -1648,6 +1711,7 @@ public RenderingHints getRenderingHints() { * @see #setTransform * @see AffineTransform */ + @Override public void transform(AffineTransform Tx) { mGraphics.transform(Tx); } @@ -1658,6 +1722,7 @@ public void transform(AffineTransform Tx) { * @see #transform * @see AffineTransform */ + @Override public void setTransform(AffineTransform Tx) { mGraphics.setTransform(Tx); } @@ -1667,6 +1732,7 @@ public void setTransform(AffineTransform Tx) { * @see #transform * @see #setTransform */ + @Override public AffineTransform getTransform() { return mGraphics.getTransform(); } @@ -1676,6 +1742,7 @@ public AffineTransform getTransform() { * @see #setPaint * @see java.awt.Graphics#setColor */ + @Override public Paint getPaint() { return mGraphics.getPaint(); } @@ -1684,6 +1751,7 @@ public Paint getPaint() { * Returns the current Composite in the Graphics2D state. * @see #setComposite */ + @Override public Composite getComposite() { return mGraphics.getComposite(); } @@ -1700,6 +1768,7 @@ public Composite getComposite() { * @see #getBackground * @see Graphics#clearRect */ + @Override public void setBackground(Color color) { mGraphics.setBackground(color); } @@ -1708,6 +1777,7 @@ public void setBackground(Color color) { * Returns the background color used for clearing a region. * @see #setBackground */ + @Override public Color getBackground() { return mGraphics.getBackground(); } @@ -1716,6 +1786,7 @@ public Color getBackground() { * Returns the current Stroke in the Graphics2D state. * @see #setStroke */ + @Override public Stroke getStroke() { return mGraphics.getStroke(); } @@ -1729,6 +1800,7 @@ public Stroke getStroke() { * To make the clip larger, use any setClip method. * @param s The Shape to be intersected with the current clip. */ + @Override public void clip(Shape s) { mGraphics.clip(s); } @@ -1816,6 +1888,7 @@ private void addStrokeShape(Shape s) { * Notify this object when the height or width become available * for an image. */ + @Override public synchronized boolean imageUpdate(Image img, int infoFlags, int x, int y, int width, int height) { @@ -1902,6 +1975,7 @@ private synchronized void waitForDimensions(Image img) { } } + @Override public synchronized boolean imageUpdate(Image image, int flags, int x, int y, int w, int h) { diff --git a/src/java.desktop/share/classes/sun/print/PrintJob2D.java b/src/java.desktop/share/classes/sun/print/PrintJob2D.java index ee0caaa54fe0..5579005fae2c 100644 --- a/src/java.desktop/share/classes/sun/print/PrintJob2D.java +++ b/src/java.desktop/share/classes/sun/print/PrintJob2D.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -72,6 +72,7 @@ public boolean printDialog() { * the PrintGraphics interface. * @see java.awt.PrintGraphics */ + @Override public Graphics getGraphics() { /* The caller wants a Graphics instance but we do * not want them to make 2D calls. We can't hand @@ -94,6 +95,7 @@ public Graphics getGraphics() { * Except (since 1.3) when the application specifies a resolution. * In that case it is scaled accordingly. */ + @Override public Dimension getPageDimension() { return printJobDelegate.getPageDimension(); } @@ -103,6 +105,7 @@ public Dimension getPageDimension() { * Note that this doesn't have to correspond to the physical * resolution of the printer. */ + @Override public int getPageResolution() { return printJobDelegate.getPageResolution(); } @@ -110,6 +113,7 @@ public int getPageResolution() { /** * Returns true if the last page will be printed first. */ + @Override public boolean lastPageFirst() { return printJobDelegate.lastPageFirst(); } @@ -117,6 +121,7 @@ public boolean lastPageFirst() { /** * Ends the print job and does any necessary cleanup. */ + @Override public synchronized void end() { printJobDelegate.end(); } @@ -128,6 +133,7 @@ private static class PrintJobDisposerRecord implements DisposerRecord { printJobDelegate = delegate; } + @Override public void dispose() { printJobDelegate.end(); } diff --git a/src/java.desktop/share/classes/sun/print/PrintJobAttributeException.java b/src/java.desktop/share/classes/sun/print/PrintJobAttributeException.java index d97be663517f..b2e6f71873ef 100644 --- a/src/java.desktop/share/classes/sun/print/PrintJobAttributeException.java +++ b/src/java.desktop/share/classes/sun/print/PrintJobAttributeException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -42,6 +42,7 @@ class PrintJobAttributeException extends PrintException category = cat; } + @Override public Class[] getUnsupportedAttributes() { if (category == null) { return null; @@ -51,6 +52,7 @@ public Class[] getUnsupportedAttributes() { } } + @Override public Attribute[] getUnsupportedValues() { if (attr == null) { return null; diff --git a/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java b/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java index bca3301b5c9b..05c2a20b3ed0 100644 --- a/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java +++ b/src/java.desktop/share/classes/sun/print/PrintJobDelegate.java @@ -931,6 +931,7 @@ public synchronized void end() { * @throws java.awt.print.PrinterException * thrown when the print job is terminated. */ + @Override public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException { @@ -975,6 +976,7 @@ private void startPrinterJobThread() { } + @Override public void run() { try { diff --git a/src/java.desktop/share/classes/sun/print/PrintJobFlavorException.java b/src/java.desktop/share/classes/sun/print/PrintJobFlavorException.java index 0d312175466a..b9fddb1e8319 100644 --- a/src/java.desktop/share/classes/sun/print/PrintJobFlavorException.java +++ b/src/java.desktop/share/classes/sun/print/PrintJobFlavorException.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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,6 +40,7 @@ class PrintJobFlavorException extends PrintException flavor = f; } + @Override public DocFlavor[] getUnsupportedFlavors() { DocFlavor [] flavors = { flavor}; return flavors; diff --git a/src/java.desktop/share/classes/sun/print/PrinterJobWrapper.java b/src/java.desktop/share/classes/sun/print/PrinterJobWrapper.java index 970c9283b3a6..b53d7a81a519 100644 --- a/src/java.desktop/share/classes/sun/print/PrinterJobWrapper.java +++ b/src/java.desktop/share/classes/sun/print/PrinterJobWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, 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 @@ -50,18 +50,22 @@ public PrinterJob getPrinterJob() { return job; } + @Override public final Class getCategory() { return PrinterJobWrapper.class; } + @Override public final String getName() { return "printerjob-wrapper"; } + @Override public String toString() { return "printerjob-wrapper: " + job.toString(); } + @Override public int hashCode() { return job.hashCode(); } diff --git a/src/java.desktop/share/classes/sun/print/ProxyGraphics.java b/src/java.desktop/share/classes/sun/print/ProxyGraphics.java index 7795343c406f..2b666e3f7a84 100644 --- a/src/java.desktop/share/classes/sun/print/ProxyGraphics.java +++ b/src/java.desktop/share/classes/sun/print/ProxyGraphics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -68,6 +68,7 @@ Graphics getGraphics() { * @return a new graphics context that is a copy of * this graphics context. */ + @Override public Graphics create() { return new ProxyGraphics(g.create()); } @@ -106,6 +107,7 @@ public Graphics create() { * @see java.awt.Graphics#translate * @see java.awt.Graphics#clipRect */ + @Override public Graphics create(int x, int y, int width, int height) { return new ProxyGraphics(g.create(x, y, width, height)); } @@ -121,6 +123,7 @@ public Graphics create(int x, int y, int width, int height) { * @param x the x coordinate. * @param y the y coordinate. */ + @Override public void translate(int x, int y) { g.translate(x, y); } @@ -131,6 +134,7 @@ public void translate(int x, int y) { * @see java.awt.Color * @see java.awt.Graphics#setColor */ + @Override public Color getColor() { return g.getColor(); } @@ -143,6 +147,7 @@ public Color getColor() { * @see java.awt.Color * @see java.awt.Graphics#getColor */ + @Override public void setColor(Color c) { g.setColor(c); } @@ -154,6 +159,7 @@ public void setColor(Color c) { * overwrite mode. All subsequent rendering operations will * overwrite the destination with the current color. */ + @Override public void setPaintMode() { g.setPaintMode(); } @@ -173,6 +179,7 @@ public void setPaintMode() { * drawn twice, then all pixels are restored to their original values. * @param c1 the XOR alternation color */ + @Override public void setXORMode(Color c1) { g.setXORMode(c1); } @@ -183,6 +190,7 @@ public void setXORMode(Color c1) { * @see java.awt.Font * @see java.awt.Graphics#setFont */ + @Override public Font getFont() { return g.getFont(); } @@ -197,6 +205,7 @@ public Font getFont() { * @see java.awt.Graphics#drawBytes(byte[], int, int, int, int) * @see java.awt.Graphics#drawChars(char[], int, int, int, int) */ + @Override public void setFont(Font font) { g.setFont(font); } @@ -209,6 +218,7 @@ public void setFont(Font font) { * @see java.awt.FontMetrics * @see java.awt.Graphics#getFontMetrics(Font) */ + @Override public FontMetrics getFontMetrics() { return g.getFontMetrics(); } @@ -221,6 +231,7 @@ public FontMetrics getFontMetrics() { * @see java.awt.FontMetrics * @see java.awt.Graphics#getFontMetrics() */ + @Override public FontMetrics getFontMetrics(Font f) { return g.getFontMetrics(f); } @@ -243,6 +254,7 @@ public FontMetrics getFontMetrics(Font f) { * @see java.awt.Graphics#setClip(Shape) * @since 1.1 */ + @Override public Rectangle getClipBounds() { return g.getClipBounds(); } @@ -266,6 +278,7 @@ public Rectangle getClipBounds() { * @see #setClip(int, int, int, int) * @see #setClip(Shape) */ + @Override public void clipRect(int x, int y, int width, int height) { g.clipRect(x, y, width, height); } @@ -284,6 +297,7 @@ public void clipRect(int x, int y, int width, int height) { * @see java.awt.Graphics#setClip(Shape) * @since 1.1 */ + @Override public void setClip(int x, int y, int width, int height) { g.setClip(x, y, width, height); } @@ -304,6 +318,7 @@ public void setClip(int x, int y, int width, int height) { * @see java.awt.Graphics#setClip(Shape) * @since 1.1 */ + @Override public Shape getClip() { return g.getClip(); } @@ -324,6 +339,7 @@ public Shape getClip() { * @see java.awt.Graphics#setClip(int, int, int, int) * @since 1.1 */ + @Override public void setClip(Shape clip) { g.setClip(clip); } @@ -347,6 +363,7 @@ public void setClip(Shape clip) { * @param dx the horizontal distance to copy the pixels. * @param dy the vertical distance to copy the pixels. */ + @Override public void copyArea(int x, int y, int width, int height, int dx, int dy) { g.copyArea(x, y, width, height, dx, dy); @@ -361,6 +378,7 @@ public void copyArea(int x, int y, int width, int height, * @param x2 the second point's x coordinate. * @param y2 the second point's y coordinate. */ + @Override public void drawLine(int x1, int y1, int x2, int y2) { g.drawLine(x1, y1, x2, y2); } @@ -384,6 +402,7 @@ public void drawLine(int x1, int y1, int x2, int y2) { * @see java.awt.Graphics#clearRect * @see java.awt.Graphics#drawRect */ + @Override public void fillRect(int x, int y, int width, int height) { g.fillRect(x, y, width, height); } @@ -404,6 +423,7 @@ public void fillRect(int x, int y, int width, int height) { * @see java.awt.Graphics#fillRect * @see java.awt.Graphics#clearRect */ + @Override public void drawRect(int x, int y, int width, int height) { g.drawRect(x, y, width, height); } @@ -427,6 +447,7 @@ public void drawRect(int x, int y, int width, int height) { * @see java.awt.Graphics#setPaintMode * @see java.awt.Graphics#setXORMode(java.awt.Color) */ + @Override public void clearRect(int x, int y, int width, int height) { g.clearRect(x, y, width, height); } @@ -447,6 +468,7 @@ public void clearRect(int x, int y, int width, int height) { * at the four corners. * @see java.awt.Graphics#fillRoundRect */ + @Override public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { g.drawRoundRect(x, y, width, height, arcWidth, arcHeight); @@ -468,6 +490,7 @@ public void drawRoundRect(int x, int y, int width, int height, * of the arc at the four corners. * @see java.awt.Graphics#drawRoundRect */ + @Override public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { g.fillRoundRect(x, y, width, height, arcWidth, arcHeight); @@ -492,6 +515,7 @@ public void fillRoundRect(int x, int y, int width, int height, * or sunk into the surface. * @see java.awt.Graphics#fill3DRect */ + @Override public void draw3DRect(int x, int y, int width, int height, boolean raised) { g.draw3DRect(x, y, width, height, raised); @@ -512,6 +536,7 @@ public void draw3DRect(int x, int y, int width, int height, * or etched into the surface. * @see java.awt.Graphics#draw3DRect */ + @Override public void fill3DRect(int x, int y, int width, int height, boolean raised) { g.fill3DRect(x, y, width, height, raised); @@ -534,6 +559,7 @@ public void fill3DRect(int x, int y, int width, int height, * @param height the height of the oval to be drawn. * @see java.awt.Graphics#fillOval */ + @Override public void drawOval(int x, int y, int width, int height) { g.drawOval(x, y, width, height); } @@ -549,6 +575,7 @@ public void drawOval(int x, int y, int width, int height) { * @param height the height of the oval to be filled. * @see java.awt.Graphics#drawOval */ + @Override public void fillOval(int x, int y, int width, int height) { g.fillOval(x, y, width, height); } @@ -590,6 +617,7 @@ public void fillOval(int x, int y, int width, int height) { * relative to the start angle. * @see java.awt.Graphics#fillArc */ + @Override public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { g.drawArc(x, y, width, height, startAngle, arcAngle); @@ -631,6 +659,7 @@ public void drawArc(int x, int y, int width, int height, * relative to the start angle. * @see java.awt.Graphics#drawArc */ + @Override public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { @@ -649,6 +678,7 @@ public void fillArc(int x, int y, int width, int height, * @see java.awt.Graphics#drawPolygon(int[], int[], int) * @since 1.1 */ + @Override public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { g.drawPolyline(xPoints, yPoints, nPoints); @@ -673,6 +703,7 @@ public void drawPolyline(int[] xPoints, int[] yPoints, * @see java.awt.Graphics#fillPolygon * @see java.awt.Graphics#drawPolyline */ + @Override public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { g.drawPolygon(xPoints, yPoints, nPoints); @@ -685,6 +716,7 @@ public void drawPolygon(int[] xPoints, int[] yPoints, * @see java.awt.Graphics#fillPolygon * @see java.awt.Graphics#drawPolyline */ + @Override public void drawPolygon(Polygon p) { g.drawPolygon(p); } @@ -709,6 +741,7 @@ public void drawPolygon(Polygon p) { * @param nPoints the total number of points. * @see java.awt.Graphics#drawPolygon(int[], int[], int) */ + @Override public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { g.fillPolygon(xPoints, yPoints, nPoints); @@ -723,6 +756,7 @@ public void fillPolygon(int[] xPoints, int[] yPoints, * @param p the polygon to fill. * @see java.awt.Graphics#drawPolygon(int[], int[], int) */ + @Override public void fillPolygon(Polygon p) { g.fillPolygon(p); } @@ -738,6 +772,7 @@ public void fillPolygon(Polygon p) { * @see java.awt.Graphics#drawBytes * @see java.awt.Graphics#drawChars */ + @Override public void drawString(String str, int x, int y) { g.drawString(str, x, y); } @@ -754,6 +789,7 @@ public void drawString(String str, int x, int y) { * @see java.awt.Graphics#drawBytes * @see java.awt.Graphics#drawChars */ + @Override public void drawString(AttributedCharacterIterator iterator, int x, int y) { g.drawString(iterator, x, y); @@ -772,6 +808,7 @@ public void drawString(AttributedCharacterIterator iterator, * @see java.awt.Graphics#drawBytes * @see java.awt.Graphics#drawString */ + @Override public void drawChars(char[] data, int offset, int length, int x, int y) { g.drawChars(data, offset, length, x, y); } @@ -789,6 +826,7 @@ public void drawChars(char[] data, int offset, int length, int x, int y) { * @see java.awt.Graphics#drawChars * @see java.awt.Graphics#drawString */ + @Override public void drawBytes(byte[] data, int offset, int length, int x, int y) { g.drawBytes(data, offset, length, x, y); } @@ -817,6 +855,7 @@ public void drawBytes(byte[] data, int offset, int length, int x, int y) { * @see java.awt.image.ImageObserver * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) */ + @Override public boolean drawImage(Image img, int x, int y, ImageObserver observer) { return g.drawImage(img, x, y, observer); @@ -855,6 +894,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) */ + @Override public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { @@ -891,6 +931,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) */ + @Override public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { @@ -935,6 +976,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) */ + @Override public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, @@ -990,6 +1032,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.1 */ + @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, @@ -1053,6 +1096,7 @@ public boolean drawImage(Image img, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.1 */ + @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, @@ -1092,6 +1136,7 @@ public boolean drawImage(Image img, * @see java.awt.Component#getGraphics * @see java.awt.Graphics#create */ + @Override public void dispose() { g.dispose(); } @@ -1099,6 +1144,7 @@ public void dispose() { /** * Empty finalizer as no clean up needed here. */ + @Override @SuppressWarnings("removal") public void finalize() { } @@ -1108,6 +1154,7 @@ public void finalize() { * {@code Graphics} object's value. * @return a string representation of this graphics context. */ + @Override public String toString() { return getClass().getName() + "[font=" + getFont() + ",color=" + getColor() + "]"; } @@ -1116,6 +1163,7 @@ public String toString() { * @deprecated As of JDK version 1.1, * replaced by {@code getClipBounds()}. */ + @Override @Deprecated public Rectangle getClipRect() { return g.getClipRect(); @@ -1132,6 +1180,7 @@ public Rectangle getClipRect() { * @param width the width of the rectangle to test against the clip * @param height the height of the rectangle to test against the clip */ + @Override public boolean hitClip(int x, int y, int width, int height) { return g.hitClip(x, y, width, height); } @@ -1152,6 +1201,7 @@ public boolean hitClip(int x, int y, int width, int height) { * overwritten. * @return the bounding rectangle of the current clipping area. */ + @Override public Rectangle getClipBounds(Rectangle r) { return g.getClipBounds(r); } diff --git a/src/java.desktop/share/classes/sun/print/ProxyGraphics2D.java b/src/java.desktop/share/classes/sun/print/ProxyGraphics2D.java index 598bedb56138..9de9675f4d41 100644 --- a/src/java.desktop/share/classes/sun/print/ProxyGraphics2D.java +++ b/src/java.desktop/share/classes/sun/print/ProxyGraphics2D.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -95,6 +95,7 @@ public void setDelegate(Graphics2D graphics) { mGraphics = graphics; } + @Override public PrinterJob getPrinterJob() { return mPrinterJob; } @@ -102,6 +103,7 @@ public PrinterJob getPrinterJob() { /** * Returns the device configuration associated with this Graphics2D. */ + @Override public GraphicsConfiguration getDeviceConfiguration() { return ((RasterPrinterJob)mPrinterJob).getPrinterGraphicsConfig(); } @@ -115,6 +117,7 @@ public GraphicsConfiguration getDeviceConfiguration() { * this graphics context. * @since 1.0 */ + @Override public Graphics create() { return new ProxyGraphics2D((Graphics2D) mGraphics.create(), mPrinterJob); @@ -132,6 +135,7 @@ public Graphics create() { * @param y the y coordinate. * @since 1.0 */ + @Override public void translate(int x, int y) { mGraphics.translate(x, y); } @@ -147,6 +151,7 @@ public void translate(int x, int y) { * [ 0 0 1 ] * */ + @Override public void translate(double tx, double ty) { mGraphics.translate(tx, ty); } @@ -165,6 +170,7 @@ public void translate(double tx, double ty) { * x axis toward the positive y axis. * @param theta The angle of rotation in radians. */ + @Override public void rotate(double theta) { mGraphics.rotate(theta); } @@ -184,6 +190,7 @@ public void rotate(double theta) { * @param x The x coordinate of the origin of the rotation * @param y The x coordinate of the origin of the rotation */ + @Override public void rotate(double theta, double x, double y) { mGraphics.rotate(theta, x, y); } @@ -199,6 +206,7 @@ public void rotate(double theta, double x, double y) { * [ 0 0 1 ] * */ + @Override public void scale(double sx, double sy) { mGraphics.scale(sx, sy); } @@ -218,6 +226,7 @@ public void scale(double sx, double sy) { * @param shy The factor by which coordinates are shifted towards the * positive Y axis direction according to their X coordinate */ + @Override public void shear(double shx, double shy) { mGraphics.shear(shx, shy); } @@ -229,6 +238,7 @@ public void shear(double shx, double shy) { * @see java.awt.Graphics#setColor * @since 1.0 */ + @Override public Color getColor() { return mGraphics.getColor(); } @@ -242,6 +252,7 @@ public Color getColor() { * @see java.awt.Graphics#getColor * @since 1.0 */ + @Override public void setColor(Color c) { mGraphics.setColor(c); } @@ -254,6 +265,7 @@ public void setColor(Color c) { * overwrite the destination with the current color. * @since 1.0 */ + @Override public void setPaintMode() { mGraphics.setPaintMode(); } @@ -274,6 +286,7 @@ public void setPaintMode() { * @param c1 the XOR alternation color * @since 1.0 */ + @Override public void setXORMode(Color c1) { mGraphics.setXORMode(c1); } @@ -285,6 +298,7 @@ public void setXORMode(Color c1) { * @see java.awt.Graphics#setFont * @since 1.0 */ + @Override public Font getFont() { return mGraphics.getFont(); } @@ -300,6 +314,7 @@ public Font getFont() { * @see java.awt.Graphics#drawBytes(byte[], int, int, int, int) * @since 1.0 */ + @Override public void setFont(Font font) { mGraphics.setFont(font); } @@ -313,6 +328,7 @@ public void setFont(Font font) { * @see java.awt.Graphics#getFontMetrics() * @since 1.0 */ + @Override public FontMetrics getFontMetrics(Font f) { return mGraphics.getFontMetrics(f); } @@ -321,6 +337,7 @@ public FontMetrics getFontMetrics(Font f) { * Get the rendering context of the font * within this Graphics2D context. */ + @Override public FontRenderContext getFontRenderContext() { return mGraphics.getFontRenderContext(); } @@ -336,6 +353,7 @@ public FontRenderContext getFontRenderContext() { * @see java.awt.Graphics#setClip(Shape) * @since 1.1 */ + @Override public Rectangle getClipBounds() { return mGraphics.getClipBounds(); } @@ -355,6 +373,7 @@ public Rectangle getClipBounds() { * @see #setClip(int, int, int, int) * @see #setClip(Shape) */ + @Override public void clipRect(int x, int y, int width, int height) { mGraphics.clipRect(x, y, width, height); } @@ -372,6 +391,7 @@ public void clipRect(int x, int y, int width, int height) { * @see java.awt.Graphics#setClip(Shape) * @since 1.1 */ + @Override public void setClip(int x, int y, int width, int height) { mGraphics.setClip(x, y, width, height); } @@ -386,6 +406,7 @@ public void setClip(int x, int y, int width, int height) { * @see java.awt.Graphics#setClip(Shape) * @since 1.1 */ + @Override public Shape getClip() { return mGraphics.getClip(); } @@ -404,6 +425,7 @@ public Shape getClip() { * @see java.awt.Graphics#setClip(int, int, int, int) * @since 1.1 */ + @Override public void setClip(Shape clip) { mGraphics.setClip(clip); } @@ -429,6 +451,7 @@ public void setClip(Shape clip) { * @param dy the vertical distance to copy the pixels. * @since 1.0 */ + @Override public void copyArea(int x, int y, int width, int height, int dx, int dy) { mGraphics.copyArea(x, y, width, height, dx, dy); @@ -444,6 +467,7 @@ public void copyArea(int x, int y, int width, int height, * @param y2 the second point's y coordinate. * @since 1.0 */ + @Override public void drawLine(int x1, int y1, int x2, int y2) { mGraphics.drawLine(x1, y1, x2, y2); } @@ -469,6 +493,7 @@ public void drawLine(int x1, int y1, int x2, int y2) { * @see java.awt.Graphics#clearRect * @since 1.0 */ + @Override public void fillRect(int x, int y, int width, int height) { mGraphics.fillRect(x, y, width, height); } @@ -493,6 +518,7 @@ public void fillRect(int x, int y, int width, int height) { * @see java.awt.Graphics#setXORMode(java.awt.Color) * @since 1.0 */ + @Override public void clearRect(int x, int y, int width, int height) { mGraphics.clearRect(x, y, width, height); } @@ -514,6 +540,7 @@ public void clearRect(int x, int y, int width, int height) { * @see java.awt.Graphics#fillRoundRect * @since 1.0 */ + @Override public void drawRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { mGraphics.drawRoundRect(x, y, width, height, arcWidth, arcHeight); @@ -536,6 +563,7 @@ public void drawRoundRect(int x, int y, int width, int height, * @see java.awt.Graphics#drawRoundRect * @since 1.0 */ + @Override public void fillRoundRect(int x, int y, int width, int height, int arcWidth, int arcHeight) { mGraphics.fillRoundRect(x, y, width, height, arcWidth, arcHeight); @@ -559,6 +587,7 @@ public void fillRoundRect(int x, int y, int width, int height, * @see java.awt.Graphics#fillOval * @since 1.0 */ + @Override public void drawOval(int x, int y, int width, int height) { mGraphics.drawOval(x, y, width, height); } @@ -575,6 +604,7 @@ public void drawOval(int x, int y, int width, int height) { * @see java.awt.Graphics#drawOval * @since 1.0 */ + @Override public void fillOval(int x, int y, int width, int height) { mGraphics.fillOval(x, y, width, height); } @@ -609,6 +639,7 @@ public void fillOval(int x, int y, int width, int height) { * @see java.awt.Graphics#fillArc * @since 1.0 */ + @Override public void drawArc(int x, int y, int width, int height, int startAngle, int arcAngle) { mGraphics.drawArc(x, y, width, height, startAngle, arcAngle); @@ -643,6 +674,7 @@ public void drawArc(int x, int y, int width, int height, * @see java.awt.Graphics#drawArc * @since 1.0 */ + @Override public void fillArc(int x, int y, int width, int height, int startAngle, int arcAngle) { mGraphics.fillArc(x, y, width, height, startAngle, arcAngle); @@ -660,6 +692,7 @@ public void fillArc(int x, int y, int width, int height, * @see java.awt.Graphics#drawPolygon(int[], int[], int) * @since 1.1 */ + @Override public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) { mGraphics.drawPolyline(xPoints, yPoints, nPoints); @@ -685,6 +718,7 @@ public void drawPolyline(int[] xPoints, int[] yPoints, * @see java.awt.Graphics#drawPolyline * @since 1.0 */ + @Override public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) { mGraphics.drawPolygon(xPoints, yPoints, nPoints); @@ -711,6 +745,7 @@ public void drawPolygon(int[] xPoints, int[] yPoints, * @see java.awt.Graphics#drawPolygon(int[], int[], int) * @since 1.0 */ + @Override public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) { mGraphics.fillPolygon(xPoints, yPoints, nPoints); @@ -728,6 +763,7 @@ public void fillPolygon(int[] xPoints, int[] yPoints, * @see java.awt.Graphics#drawChars * @since 1.0 */ + @Override public void drawString(String str, int x, int y) { mGraphics.drawString(str, x, y); } @@ -752,6 +788,7 @@ public void drawString(String str, int x, int y) { * @see #setComposite * @see #setClip */ + @Override public void drawString(AttributedCharacterIterator iterator, int x, int y) { mGraphics.drawString(iterator, x, y); @@ -777,6 +814,7 @@ public void drawString(AttributedCharacterIterator iterator, * @see #setComposite * @see #setClip */ + @Override public void drawString(AttributedCharacterIterator iterator, float x, float y) { mGraphics.drawString(iterator, x, y); @@ -807,6 +845,7 @@ public void drawString(AttributedCharacterIterator iterator, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, ImageObserver observer) { @@ -847,6 +886,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, int width, int height, ImageObserver observer) { @@ -885,6 +925,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, Color bgcolor, ImageObserver observer) { @@ -944,6 +985,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.0 */ + @Override public boolean drawImage(Image img, int x, int y, int width, int height, Color bgcolor, @@ -1013,6 +1055,7 @@ public boolean drawImage(Image img, int x, int y, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.1 */ + @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, @@ -1075,6 +1118,7 @@ public boolean drawImage(Image img, * @see java.awt.image.ImageObserver#imageUpdate(java.awt.Image, int, int, int, int, int) * @since 1.1 */ + @Override public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, @@ -1195,6 +1239,7 @@ private BufferedImage getBufferedImageCopy(Image img, Color bgcolor) { * @see #clip * @see #setClip */ + @Override public void drawRenderedImage(RenderedImage img, AffineTransform xform) { mGraphics.drawRenderedImage(img, xform); @@ -1202,6 +1247,7 @@ public void drawRenderedImage(RenderedImage img, + @Override public void drawRenderableImage(RenderableImage img, AffineTransform xform) { @@ -1255,6 +1301,7 @@ public void drawRenderableImage(RenderableImage img, * @see java.awt.Graphics#create * @since 1.0 */ + @Override public void dispose() { mGraphics.dispose(); } @@ -1262,6 +1309,7 @@ public void dispose() { /** * Empty finalizer as no clean up needed here. */ + @Override @SuppressWarnings("removal") public void finalize() { } @@ -1283,6 +1331,7 @@ public void finalize() { * @see #setClip * @see #setComposite */ + @Override public void draw(Shape s) { mGraphics.draw(s); } @@ -1307,6 +1356,7 @@ public void draw(Shape s) { * @see #clip * @see #setClip */ + @Override public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) { @@ -1331,6 +1381,7 @@ public boolean drawImage(Image img, * @see #clip * @see #setClip */ + @Override public void drawImage(BufferedImage img, BufferedImageOp op, int x, @@ -1355,6 +1406,7 @@ public void drawImage(BufferedImage img, * @see #clip * @see #setClip */ + @Override public void drawString(String str, float x, float y) { @@ -1376,6 +1428,7 @@ public void drawString(String str, * @see #clip * @see #setClip */ + @Override public void drawGlyphVector(GlyphVector g, float x, float y) { @@ -1394,6 +1447,7 @@ public void drawGlyphVector(GlyphVector g, * @see #clip * @see #setClip */ + @Override public void fill(Shape s) { mGraphics.fill(s); } @@ -1416,6 +1470,7 @@ public void fill(Shape s) { * @see #clip * @see #setClip */ + @Override public boolean hit(Rectangle rect, Shape s, boolean onStroke) { @@ -1433,6 +1488,7 @@ public boolean hit(Rectangle rect, * @see java.awt.Graphics#setPaintMode * @see java.awt.AlphaComposite */ + @Override public void setComposite(Composite comp) { mGraphics.setComposite(comp); } @@ -1446,6 +1502,7 @@ public void setComposite(Composite comp) { * @see java.awt.GradientPaint * @see java.awt.TexturePaint */ + @Override public void setPaint(Paint paint) { mGraphics.setPaint(paint); } @@ -1456,6 +1513,7 @@ public void setPaint(Paint paint) { * the rendering process. * @see java.awt.BasicStroke */ + @Override public void setStroke(Stroke s) { mGraphics.setStroke(s); } @@ -1469,6 +1527,7 @@ public void setStroke(Stroke s) { * hint category. * @see RenderingHints */ + @Override public void setRenderingHint(Key hintCategory, Object hintValue) { mGraphics.setRenderingHint(hintCategory, hintValue); } @@ -1479,6 +1538,7 @@ public void setRenderingHint(Key hintCategory, Object hintValue) { * @return The preferences for rendering algorithms. * @see RenderingHints */ + @Override public Object getRenderingHint(Key hintCategory) { return mGraphics.getRenderingHint(hintCategory); } @@ -1490,6 +1550,7 @@ public Object getRenderingHint(Key hintCategory) { * @param hints The rendering hints to be set * @see RenderingHints */ + @Override public void setRenderingHints(Map hints) { mGraphics.setRenderingHints(hints); } @@ -1501,6 +1562,7 @@ public void setRenderingHints(Map hints) { * @param hints The rendering hints to be set * @see RenderingHints */ + @Override public void addRenderingHints(Map hints) { mGraphics.addRenderingHints(hints); } @@ -1511,6 +1573,7 @@ public void addRenderingHints(Map hints) { * overall time/quality trade-off in the rendering process. * @see RenderingHints */ + @Override public RenderingHints getRenderingHints() { return mGraphics.getRenderingHints(); } @@ -1532,6 +1595,7 @@ public RenderingHints getRenderingHints() { * @see #setTransform * @see AffineTransform */ + @Override public void transform(AffineTransform Tx) { mGraphics.transform(Tx); } @@ -1542,6 +1606,7 @@ public void transform(AffineTransform Tx) { * @see #transform * @see AffineTransform */ + @Override public void setTransform(AffineTransform Tx) { mGraphics.setTransform(Tx); } @@ -1551,6 +1616,7 @@ public void setTransform(AffineTransform Tx) { * @see #transform * @see #setTransform */ + @Override public AffineTransform getTransform() { return mGraphics.getTransform(); } @@ -1560,6 +1626,7 @@ public AffineTransform getTransform() { * @see #setPaint * @see java.awt.Graphics#setColor */ + @Override public Paint getPaint() { return mGraphics.getPaint(); } @@ -1568,6 +1635,7 @@ public Paint getPaint() { * Returns the current Composite in the Graphics2D state. * @see #setComposite */ + @Override public Composite getComposite() { return mGraphics.getComposite(); } @@ -1584,6 +1652,7 @@ public Composite getComposite() { * @see #getBackground * @see Graphics#clearRect */ + @Override public void setBackground(Color color) { mGraphics.setBackground(color); } @@ -1592,6 +1661,7 @@ public void setBackground(Color color) { * Returns the background color used for clearing a region. * @see #setBackground */ + @Override public Color getBackground() { return mGraphics.getBackground(); } @@ -1600,6 +1670,7 @@ public Color getBackground() { * Returns the current Stroke in the Graphics2D state. * @see #setStroke */ + @Override public Stroke getStroke() { return mGraphics.getStroke(); } @@ -1613,6 +1684,7 @@ public Stroke getStroke() { * To make the clip larger, use any setClip method. * @param s The Shape to be intersected with the current clip. */ + @Override public void clip(Shape s) { mGraphics.clip(s); } diff --git a/src/java.desktop/share/classes/sun/print/ProxyPrintGraphics.java b/src/java.desktop/share/classes/sun/print/ProxyPrintGraphics.java index 7bf125f185ff..6bccd59e2377 100644 --- a/src/java.desktop/share/classes/sun/print/ProxyPrintGraphics.java +++ b/src/java.desktop/share/classes/sun/print/ProxyPrintGraphics.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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,6 +49,7 @@ public ProxyPrintGraphics(Graphics graphics, PrintJob thePrintJob) { * Returns the PrintJob object from which this PrintGraphics * object originated. */ + @Override public PrintJob getPrintJob() { return printJob; } @@ -59,6 +60,7 @@ public PrintJob getPrintJob() { * @return a new graphics context that is a copy of * this graphics context. */ + @Override public Graphics create() { return new ProxyPrintGraphics(getGraphics().create(), printJob); } @@ -80,11 +82,13 @@ public Graphics create() { * @see java.awt.Graphics#translate * @see java.awt.Graphics#clipRect */ + @Override public Graphics create(int x, int y, int width, int height) { Graphics g = getGraphics().create(x, y, width, height); return new ProxyPrintGraphics(g, printJob); } + @Override public Graphics getGraphics() { return super.getGraphics(); } @@ -96,6 +100,7 @@ public Graphics getGraphics() { * We will preserve that behaviour and there is consequently no need * to take any action in this dispose method. */ + @Override public void dispose() { super.dispose(); } diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java index b28723f94a62..db0276ae1001 100644 --- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java +++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java @@ -451,6 +451,7 @@ protected static PrintService lookupDefaultPrintService() { * @return the service for this printer job. * */ + @Override public PrintService getPrintService() { if (myService == null) { PrintService svc = PrintServiceLookup.lookupDefaultPrintService(); @@ -489,6 +490,7 @@ public PrintService getPrintService() { * @throws PrinterException if the specified service does not support * 2D printing or no longer available. */ + @Override public void setPrintService(PrintService service) throws PrinterException { if (service == null) { @@ -713,6 +715,7 @@ protected void updateAttributesWithPageFormat(PrintService service, * @see java.awt.GraphicsEnvironment#isHeadless * @since 1.2 */ + @Override public PageFormat pageDialog(PageFormat page) throws HeadlessException { if (GraphicsEnvironment.isHeadless()) { @@ -755,6 +758,7 @@ public PageFormat pageDialog(PageFormat page) * return a PageFormat corresponding to the updated attributes, * or null if the user cancelled the dialog. */ + @Override @SuppressWarnings("deprecation") public PageFormat pageDialog(final PrintRequestAttributeSet attributes) throws HeadlessException { @@ -920,6 +924,7 @@ protected PageFormat getPageFormatFromAttributes() { * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ + @Override public boolean printDialog(final PrintRequestAttributeSet attributes) throws HeadlessException { if (GraphicsEnvironment.isHeadless()) { @@ -1049,6 +1054,7 @@ public boolean printDialog(final PrintRequestAttributeSet attributes) * returns true. * @see java.awt.GraphicsEnvironment#isHeadless */ + @Override public boolean printDialog() throws HeadlessException { if (GraphicsEnvironment.isHeadless()) { @@ -1105,6 +1111,7 @@ public boolean printDialog() throws HeadlessException { * for each page is the default page format. * @param painter Called to render each page of the document. */ + @Override public void setPrintable(Printable painter) { setPageable(new OpenBook(defaultPage(new PageFormat()), painter)); } @@ -1117,6 +1124,7 @@ public void setPrintable(Printable painter) { * @param format The size and orientation of each page to * be printed. */ + @Override public void setPrintable(Printable painter, PageFormat format) { setPageable(new OpenBook(format, painter)); updatePageAttributes(getPrintService(), format); @@ -1132,6 +1140,7 @@ public void setPrintable(Printable painter, PageFormat format) { * @see PageFormat * @see Printable */ + @Override public void setPageable(Pageable document) throws NullPointerException { if (document != null) { mDocument = document; @@ -1430,6 +1439,7 @@ protected void spoolToService(PrintService psvc, * @see java.awt.print.Pageable * @see java.awt.print.Printable */ + @Override public void print() throws PrinterException { print(attributes); } @@ -1441,6 +1451,7 @@ protected void debug_println(String str) { } } + @Override public void print(PrintRequestAttributeSet attributes) throws PrinterException { @@ -1717,6 +1728,7 @@ protected void validatePaper(Paper origPaper, Paper newPaper) { * Platform subclasses which can access the actual default paper size * for a printer may override this method. */ + @Override public PageFormat defaultPage(PageFormat page) { PageFormat newPage = (PageFormat)page.clone(); newPage.setOrientation(PageFormat.PORTRAIT); @@ -1772,6 +1784,7 @@ public PageFormat defaultPage(PageFormat page) { * The passed in PageFormat is cloned and altered to be usable on * the PrinterJob's current printer. */ + @Override public PageFormat validatePage(PageFormat page) { PageFormat newPage = (PageFormat)page.clone(); Paper newPaper = new Paper(); @@ -1784,6 +1797,7 @@ public PageFormat validatePage(PageFormat page) { /** * Set the number of copies to be printed. */ + @Override public void setCopies(int copies) { mNumCopies = copies; } @@ -1791,6 +1805,7 @@ public void setCopies(int copies) { /** * Get the number of copies to be printed. */ + @Override public int getCopies() { return mNumCopies; } @@ -1805,6 +1820,7 @@ protected int getCopiesInt() { /** * Get the name of the printing user. */ + @Override public String getUserName() { return System.getProperty("user.name"); } @@ -1824,6 +1840,7 @@ protected String getUserNameInt() { * Set the name of the document to be printed. * The document name can not be null. */ + @Override public void setJobName(String jobName) { if (jobName != null) { mDocName = jobName; @@ -1835,6 +1852,7 @@ public void setJobName(String jobName) { /** * Get the name of the document to be printed. */ + @Override public String getJobName() { return mDocName; } @@ -2396,6 +2414,7 @@ protected int printPage(Pageable document, int pageIndex) * chance. If there is no print job in progress then * this call does nothing. */ + @Override public void cancel() { synchronized (this) { if (performingPrinting) { diff --git a/src/java.desktop/share/classes/sun/print/ServiceDialog.java b/src/java.desktop/share/classes/sun/print/ServiceDialog.java index d6d3b92ee8d4..39dd3d8d997f 100644 --- a/src/java.desktop/share/classes/sun/print/ServiceDialog.java +++ b/src/java.desktop/share/classes/sun/print/ServiceDialog.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -210,6 +210,7 @@ void initPrintDialog(int x, int y, c.add(pnlSouth, BorderLayout.SOUTH); addWindowListener(new WindowAdapter() { + @Override public void windowClosing(WindowEvent event) { dispose(CANCEL); } @@ -274,6 +275,7 @@ void initPageDialog(int x, int y, c.add(pnlSouth, BorderLayout.SOUTH); addWindowListener(new WindowAdapter() { + @Override public void windowClosing(WindowEvent event) { dispose(CANCEL); } @@ -290,6 +292,7 @@ public void windowClosing(WindowEvent event) { */ private void handleEscKey(JButton btnCancel) { Action cancelKeyAction = new AbstractAction() { + @Override public void actionPerformed(ActionEvent e) { dispose(CANCEL); } @@ -351,6 +354,7 @@ public void dispose(int status) { super.dispose(); } + @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); boolean approved = false; @@ -754,6 +758,7 @@ private JLabel addLabel(String text, return label; } + @Override @SuppressWarnings("deprecation") public void actionPerformed(ActionEvent e) { Object source = e.getSource(); @@ -798,6 +803,7 @@ public void actionPerformed(ActionEvent e) { } } + @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { int index = cbName.getSelectedIndex(); @@ -844,10 +850,12 @@ public void itemStateChanged(ItemEvent e) { } } + @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { changedService = false; } + @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (changedService) { changedService = false; @@ -855,6 +863,7 @@ public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { } } + @Override public void popupMenuCanceled(PopupMenuEvent e) { } @@ -1006,6 +1015,7 @@ public PrintRangePanel() { addToGB(pnlBottom, this, gridbag, c); } + @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); SunPageSelection select = SunPageSelection.ALL; @@ -1028,6 +1038,7 @@ public void actionPerformed(ActionEvent e) { } } + @Override public void focusLost(FocusEvent e) { Object source = e.getSource(); @@ -1036,6 +1047,7 @@ public void focusLost(FocusEvent e) { } } + @Override public void focusGained(FocusEvent e) {} private void setupRangeWidgets() { @@ -1175,6 +1187,7 @@ public CopiesPanel() { addToGB(cbCollate, this, gridbag, c); } + @Override public void actionPerformed(ActionEvent e) { if (cbCollate.isSelected()) { asCurrent.add(SheetCollate.COLLATED); @@ -1183,6 +1196,7 @@ public void actionPerformed(ActionEvent e) { } } + @Override public void stateChanged(ChangeEvent e) { updateCollateCB(); @@ -1440,16 +1454,19 @@ public MarginsPanel() { } + @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); updateMargins(source); } + @Override public void focusLost(FocusEvent e) { Object source = e.getSource(); updateMargins(source); } + @Override public void focusGained(FocusEvent e) {} /* Get the numbers, use to create a MPA. @@ -1905,6 +1922,7 @@ private String getMediaName(String key) { } } + @Override public void itemStateChanged(ItemEvent e) { Object source = e.getSource(); @@ -2128,6 +2146,7 @@ public OrientationPanel() { addToGB(rbRevLandscape, this, gridbag, c); } + @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); @@ -2327,6 +2346,7 @@ public ChromaticityPanel() { addToGB(rbColor, this, gridbag, c); } + @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); @@ -2421,6 +2441,7 @@ public QualityPanel() { addToGB(rbHigh, this, gridbag, c); } + @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); @@ -2531,6 +2552,7 @@ public SidesPanel() { addToGB(rbDuplex, this, gridbag, c); } + @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); @@ -2674,6 +2696,7 @@ public JobAttributesPanel() { addToGB(tfUserName, this, gridbag, c); } + @Override public void actionPerformed(ActionEvent e) { if (cbJobSheets.isSelected()) { asCurrent.add(JobSheets.STANDARD); @@ -2682,10 +2705,12 @@ public void actionPerformed(ActionEvent e) { } } + @Override public void stateChanged(ChangeEvent e) { asCurrent.add(new JobPriority(snModel.getNumber().intValue())); } + @Override public void focusLost(FocusEvent e) { Object source = e.getSource(); @@ -2698,6 +2723,7 @@ public void focusLost(FocusEvent e) { } } + @Override public void focusGained(FocusEvent e) {} public void updateInfo() { @@ -2808,6 +2834,7 @@ public OutputPanel() { addToGB(cbOutput, this, gridbag, c); } + @Override public void itemStateChanged(ItemEvent e) { Object source = e.getSource(); @@ -2908,6 +2935,7 @@ public boolean isSameAs(Object source) { return (rb == source); } + @Override public void setEnabled(boolean enabled) { rb.setEnabled(enabled); lbl.setEnabled(enabled); @@ -2929,6 +2957,7 @@ public void setSelected(boolean selected) { */ @SuppressWarnings("serial") // JDK implementation class private static class ValidatingFileChooser extends JFileChooser { + @Override public void approveSelection() { File selected = getSelectedFile(); boolean exists = selected.exists(); diff --git a/src/java.desktop/share/classes/sun/print/ServiceNotifier.java b/src/java.desktop/share/classes/sun/print/ServiceNotifier.java index f42489debc7c..702b3596b73e 100644 --- a/src/java.desktop/share/classes/sun/print/ServiceNotifier.java +++ b/src/java.desktop/share/classes/sun/print/ServiceNotifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -98,6 +98,7 @@ void wake() { * a minimum of 15 seconds. Ensures this won't take more than 10% * of available time. */ + @Override public void run() { long minSleepTime = 15000; diff --git a/src/java.desktop/share/classes/sun/print/SunAlternateMedia.java b/src/java.desktop/share/classes/sun/print/SunAlternateMedia.java index cf88c671cca2..24ac8b5df920 100644 --- a/src/java.desktop/share/classes/sun/print/SunAlternateMedia.java +++ b/src/java.desktop/share/classes/sun/print/SunAlternateMedia.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -54,14 +54,17 @@ public Media getMedia() { return media; } + @Override public final Class getCategory() { return SunAlternateMedia.class; } + @Override public final String getName() { return "sun-alternate-media"; } + @Override public String toString() { return "alternate-media: " + media.toString(); } @@ -70,6 +73,7 @@ public String toString() { * Returns a hash code value for this enumeration value. The hash code is * just this enumeration value's integer value. */ + @Override public int hashCode() { return media.hashCode(); } diff --git a/src/java.desktop/share/classes/sun/print/SunMinMaxPage.java b/src/java.desktop/share/classes/sun/print/SunMinMaxPage.java index b4a5054ee589..fa4630bfcd80 100644 --- a/src/java.desktop/share/classes/sun/print/SunMinMaxPage.java +++ b/src/java.desktop/share/classes/sun/print/SunMinMaxPage.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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,6 +40,7 @@ public SunMinMaxPage(int min, int max) { page_max = max; } + @Override public Class getCategory() { return SunMinMaxPage.class; } @@ -52,6 +53,7 @@ public int getMax() { return page_max; } + @Override public String getName() { return "sun-page-minmax"; } diff --git a/src/java.desktop/share/classes/sun/print/SunPageSelection.java b/src/java.desktop/share/classes/sun/print/SunPageSelection.java index 6d7af26aadde..ec66c6485175 100644 --- a/src/java.desktop/share/classes/sun/print/SunPageSelection.java +++ b/src/java.desktop/share/classes/sun/print/SunPageSelection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -44,14 +44,17 @@ public SunPageSelection(int value) { pages = value; } + @Override public Class getCategory() { return SunPageSelection.class; } + @Override public String getName() { return "sun-page-selection"; } + @Override public String toString() { return "page-selection: " + pages; } diff --git a/src/java.desktop/share/legal/freetype.md b/src/java.desktop/share/legal/freetype.md index 0c972d0fa994..d7c9b0fe0026 100644 --- a/src/java.desktop/share/legal/freetype.md +++ b/src/java.desktop/share/legal/freetype.md @@ -1,4 +1,4 @@ -## The FreeType Project: Freetype v2.14.3 +## The FreeType Project: Freetype v2.15.0 ### FreeType Notice diff --git a/src/java.desktop/share/native/common/awt/debug/debug_assert.c b/src/java.desktop/share/native/common/awt/debug/debug_assert.c index eb3e380c8e94..12f32f2d5953 100644 --- a/src/java.desktop/share/native/common/awt/debug/debug_assert.c +++ b/src/java.desktop/share/native/common/awt/debug/debug_assert.c @@ -54,7 +54,3 @@ void DAssert_SetCallback(DASSERT_CALLBACK pfn) { #endif /* defined(DEBUG) */ -/* The following line is only here to prevent compiler warnings - * on release (non-debug) builds - */ -static int dummyVariable = 0; diff --git a/src/java.desktop/share/native/common/awt/debug/debug_mem.c b/src/java.desktop/share/native/common/awt/debug/debug_mem.c index 311476695dd7..afb97c90a667 100644 --- a/src/java.desktop/share/native/common/awt/debug/debug_mem.c +++ b/src/java.desktop/share/native/common/awt/debug/debug_mem.c @@ -336,7 +336,3 @@ void DMem_DisableMutex() { #endif /* defined(DEBUG) */ -/* The following line is only here to prevent compiler warnings - * on release (non-debug) builds - */ -static int dummyVariable = 0; diff --git a/src/java.desktop/share/native/common/awt/debug/debug_trace.h b/src/java.desktop/share/native/common/awt/debug/debug_trace.h index 1f7064ef0036..2d054d8be60a 100644 --- a/src/java.desktop/share/native/common/awt/debug/debug_trace.h +++ b/src/java.desktop/share/native/common/awt/debug/debug_trace.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, 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 @@ -62,7 +62,11 @@ JNIEXPORT void JNICALL DTrace_VPrint(const char * file, int line, int argc, cons JNIEXPORT void JNICALL DTrace_VPrintln(const char * file, int line, int argc, const char * fmt, va_list arglist); /* each file includes this flag indicating module trace status */ -static dtrace_id _Dt_FileTraceId = UNDEFINED_TRACE_ID; +#if defined(__GNUC__) +static dtrace_id _Dt_FileTraceId __attribute__((unused)) = UNDEFINED_TRACE_ID; +#else +static dtrace_id _Dt_FileTraceId = UNDEFINED_TRACE_ID; +#endif /* not meant to be called from client code-- * it's just a template for the other macros diff --git a/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c b/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c index 64a0579b90ea..dd282324df38 100644 --- a/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c +++ b/src/java.desktop/share/native/libawt/awt/medialib/awt_ImagingLib.c @@ -1211,7 +1211,6 @@ static int lookupShortData(mlib_image* src, mlib_image* dst, LookupArrayInfo* lookup) { int x, y; - unsigned int mask = NLUT-1; unsigned short* srcLine = (unsigned short*)src->data; unsigned char* dstLine = (unsigned char*)dst->data; @@ -2115,7 +2114,6 @@ allocateArray(JNIEnv *env, BufImageS_t *imageP, unsigned char *cDataP; RasterS_t *rasterP = &imageP->raster; ColorModelS_t *cmP = &imageP->cmodel; - int dataType = BYTE_DATA_TYPE; int width; int height; HintS_t *hintP = &imageP->hints; @@ -2134,7 +2132,6 @@ allocateArray(JNIEnv *env, BufImageS_t *imageP, /* around pointers and incrementing the width/height */ if (cvtToDefault) { - int status = 0; *mlibImagePP = (*sMlibSysFns.createFP)(MLIB_BYTE, 4, width, height); if (*mlibImagePP == NULL) { return -1; @@ -2262,7 +2259,6 @@ allocateRasterArray(JNIEnv *env, RasterS_t *rasterP, mlib_image **mlibImagePP, void **dataPP, int isSrc) { void *dataP; unsigned char *cDataP; - int dataType = BYTE_DATA_TYPE; int width; int height; int dataSize; diff --git a/src/java.desktop/share/native/libawt/java2d/Disposer.c b/src/java.desktop/share/native/libawt/java2d/Disposer.c index d27157e1a890..aff1904b0602 100644 --- a/src/java.desktop/share/native/libawt/java2d/Disposer.c +++ b/src/java.desktop/share/native/libawt/java2d/Disposer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, 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 @@ -48,7 +48,7 @@ Disposer_AddRecord(JNIEnv *env, jobject obj, GeneralDisposeFunc disposer, jlong if (dispClass == NULL) { /* Needed to initialize the Disposer class as it may be not yet referenced */ - jclass clazz = (*env)->FindClass(env, "sun/java2d/Disposer"); + (*env)->FindClass(env, "sun/java2d/Disposer"); if ((*env)->ExceptionCheck(env)) { // If there's exception pending, we'll just return. return; diff --git a/src/java.desktop/share/native/libawt/java2d/loops/AnyByteBinary.h b/src/java.desktop/share/native/libawt/java2d/loops/AnyByteBinary.h index bf50ff1a3733..46b87abf5f1c 100644 --- a/src/java.desktop/share/native/libawt/java2d/loops/AnyByteBinary.h +++ b/src/java.desktop/share/native/libawt/java2d/loops/AnyByteBinary.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -190,16 +190,14 @@ DSTTYPE ## DataType *DSTPTR = (DSTTYPE ## DataType *) (DSTBASE); \ jint srcScan = (SRCINFO)->scanStride; \ jint dstScan = (DSTINFO)->scanStride; \ - jint srcx1 = (SRCINFO)->bounds.x1; \ - jint dstx1 = (DSTINFO)->bounds.x1; \ Init ## DSTTYPE ## StoreVarsY(DSTPREFIX, DSTINFO); \ srcScan -= (WIDTH) * SRCTYPE ## PixelStride; \ dstScan -= (WIDTH) * DSTTYPE ## PixelStride; \ do { \ Declare ## SRCTYPE ## InitialLoadVars(SRCINFO, SRCPTR, SRCPREFIX, \ - srcx1) \ + (SRCINFO)->bounds.x1) \ Declare ## DSTTYPE ## InitialLoadVars(DSTINFO, DSTPTR, DSTPREFIX, \ - dstx1) \ + (DSTINFO)->bounds.x1) \ juint w = WIDTH; \ Init ## DSTTYPE ## StoreVarsX(DSTPREFIX, DSTINFO); \ do { \ @@ -265,7 +263,6 @@ void NAME_XOR_BLIT(SRC, DST)(void *srcBase, void *dstBase, \ CompositeInfo *pCompInfo) \ { \ jint xorpixel = pCompInfo->details.xorPixel; \ - juint alphamask = pCompInfo->alphaMask; \ Declare ## SRC ## LoadVars(SrcRead) \ Declare ## DST ## StoreVars(DstWrite) \ \ @@ -276,7 +273,7 @@ void NAME_XOR_BLIT(SRC, DST)(void *srcBase, void *dstBase, \ BBXorVia1IntArgb(pSrc, SRC, SrcRead, \ pDst, DST, DstWrite, \ 0, xorpixel, \ - alphamask, pDstInfo)); \ + pCompInfo->alphaMask, pDstInfo)); \ } #define DEFINE_BYTE_BINARY_SOLID_FILLRECT(DST) \ @@ -387,7 +384,6 @@ void NAME_XOR_FILLRECT(DST)(SurfaceDataRasInfo *pRasInfo, \ CompositeInfo *pCompInfo) \ { \ jint xorpixel = pCompInfo->details.xorPixel; \ - juint alphamask = pCompInfo->alphaMask; \ DST ## DataType *pPix; \ jint scan = pRasInfo->scanStride; \ juint height = hiy - loy; \ @@ -400,7 +396,7 @@ void NAME_XOR_FILLRECT(DST)(SurfaceDataRasInfo *pRasInfo, \ do { \ InitialLoad ## DST(pPix, DstPix); \ Xor ## DST ## PixelData(pPix, 0, DstPix, \ - pixel, xorpixel, alphamask); \ + pixel, xorpixel, pCompInfo->alphaMask); \ ShiftBits ## DST(DstPix); \ } while (--w > 0); \ FinalStore ## DST(pPix, DstPix); \ @@ -417,7 +413,6 @@ void NAME_XOR_FILLSPANS(DST)(SurfaceDataRasInfo *pRasInfo, \ { \ void *pBase = pRasInfo->rasBase; \ jint xorpixel = pCompInfo->details.xorPixel; \ - juint alphamask = pCompInfo->alphaMask; \ jint scan = pRasInfo->scanStride; \ jint bbox[4]; \ \ @@ -435,7 +430,7 @@ void NAME_XOR_FILLSPANS(DST)(SurfaceDataRasInfo *pRasInfo, \ do { \ InitialLoad ## DST(pPix, DstPix); \ Xor ## DST ## PixelData(pPix, 0, DstPix, \ - pixel, xorpixel, alphamask); \ + pixel, xorpixel, pCompInfo->alphaMask); \ ShiftBits ## DST(DstPix); \ } while (--relx > 0); \ FinalStore ## DST(pPix, DstPix); \ @@ -454,7 +449,6 @@ void NAME_XOR_DRAWLINE(DST)(SurfaceDataRasInfo *pRasInfo, \ CompositeInfo *pCompInfo) \ { \ jint xorpixel = pCompInfo->details.xorPixel; \ - juint alphamask = pCompInfo->alphaMask; \ jint scan = pRasInfo->scanStride; \ DST ## DataType *pPix = PtrCoord(pRasInfo->rasBase, \ x1, DST ## PixelStride, \ @@ -468,7 +462,7 @@ void NAME_XOR_DRAWLINE(DST)(SurfaceDataRasInfo *pRasInfo, \ do { \ Declare ## DST ## InitialLoadVars(pRasInfo, pPix, DstPix, x1) \ Xor ## DST ## PixelData(pPix, 0, DstPix, \ - pixel, xorpixel, alphamask); \ + pixel, xorpixel, pCompInfo->alphaMask); \ FinalStore ## DST(pPix, DstPix); \ x1 += bumpmajor; \ } while (--steps > 0); \ @@ -476,7 +470,7 @@ void NAME_XOR_DRAWLINE(DST)(SurfaceDataRasInfo *pRasInfo, \ do { \ Declare ## DST ## InitialLoadVars(pRasInfo, pPix, DstPix, x1) \ Xor ## DST ## PixelData(pPix, 0, DstPix, \ - pixel, xorpixel, alphamask); \ + pixel, xorpixel, pCompInfo->alphaMask); \ FinalStore ## DST(pPix, DstPix); \ if (error < 0) { \ x1 += bumpmajor; \ @@ -599,7 +593,6 @@ void NAME_XOR_DRAWGLYPHLIST(DST)(SurfaceDataRasInfo *pRasInfo, \ jint glyphCounter; \ jint scan = pRasInfo->scanStride; \ jint xorpixel = pCompInfo->details.xorPixel; \ - juint alphamask = pCompInfo->alphaMask; \ DST ## DataType *pPix; \ \ for (glyphCounter = 0; glyphCounter < totalGlyphs; glyphCounter++) { \ @@ -618,7 +611,7 @@ void NAME_XOR_DRAWGLYPHLIST(DST)(SurfaceDataRasInfo *pRasInfo, \ InitialLoad ## DST(pPix, DstPix); \ if (pixels[x]) { \ Xor ## DST ## PixelData(pPix, 0, DstPix, \ - fgpixel, xorpixel, alphamask); \ + fgpixel, xorpixel, pCompInfo->alphaMask); \ } \ ShiftBits ## DST(DstPix); \ } while (++x < width); \ @@ -646,8 +639,6 @@ void NAME_ALPHA_MASKBLIT(SRC, DST) \ jint srcScan = pSrcInfo->scanStride; \ jint dstScan = pDstInfo->scanStride; \ jboolean loadsrc, loaddst; \ - jint srcx1 = pSrcInfo->bounds.x1; \ - jint dstx1 = pDstInfo->bounds.x1; \ SRC ## DataType *pSrc = (SRC ## DataType *) (srcBase); \ DST ## DataType *pDst = (DST ## DataType *) (dstBase); \ Declare ## SRC ## AlphaLoadData(SrcRead) \ @@ -674,8 +665,8 @@ void NAME_ALPHA_MASKBLIT(SRC, DST) \ \ Init ## DST ## StoreVarsY(DstWrite, pDstInfo); \ do { \ - Declare ## SRC ## InitialLoadVars(pSrcInfo, pSrc, SrcRead, srcx1) \ - Declare ## DST ## InitialLoadVars(pDstInfo, pDst, DstWrite, dstx1) \ + Declare ## SRC ## InitialLoadVars(pSrcInfo, pSrc, SrcRead, pSrcInfo->bounds.x1) \ + Declare ## DST ## InitialLoadVars(pDstInfo, pDst, DstWrite, pDstInfo->bounds.x1) \ jint w = width; \ Init ## DST ## StoreVarsX(DstWrite, pDstInfo); \ do { \ diff --git a/src/java.desktop/share/native/libawt/java2d/loops/ByteIndexed.c b/src/java.desktop/share/native/libawt/java2d/loops/ByteIndexed.c index 88eea9482020..8b465d890411 100644 --- a/src/java.desktop/share/native/libawt/java2d/loops/ByteIndexed.c +++ b/src/java.desktop/share/native/libawt/java2d/loops/ByteIndexed.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, 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 @@ -205,8 +205,6 @@ void NAME_SCALE_BLIT(ByteIndexed, ByteIndexed) { DeclareByteIndexedLoadVars(SrcRead) DeclareByteIndexedLoadVars(DstRead) - jint srcScan = pSrcInfo->scanStride; - jint dstScan = pDstInfo->scanStride; DeclareByteIndexedStoreVars(DstWrite) InitByteIndexedLoadVars(SrcRead, pSrcInfo); diff --git a/src/java.desktop/share/native/libawt/java2d/loops/Index12Gray.c b/src/java.desktop/share/native/libawt/java2d/loops/Index12Gray.c index 5b95697af3c5..ebcef1350d62 100644 --- a/src/java.desktop/share/native/libawt/java2d/loops/Index12Gray.c +++ b/src/java.desktop/share/native/libawt/java2d/loops/Index12Gray.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -193,8 +193,6 @@ void NAME_SCALE_BLIT(Index12Gray, Index12Gray) { DeclareIndex8GrayLoadVars(SrcRead) DeclareIndex8GrayLoadVars(DstRead) - jint srcScan = pSrcInfo->scanStride; - jint dstScan = pDstInfo->scanStride; DeclareIndex8GrayStoreVars(DstWrite) InitIndex8GrayLoadVars(SrcRead, pSrcInfo); diff --git a/src/java.desktop/share/native/libawt/java2d/loops/Index8Gray.c b/src/java.desktop/share/native/libawt/java2d/loops/Index8Gray.c index f72406e904b9..3873fe46cb28 100644 --- a/src/java.desktop/share/native/libawt/java2d/loops/Index8Gray.c +++ b/src/java.desktop/share/native/libawt/java2d/loops/Index8Gray.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, 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 @@ -190,8 +190,6 @@ void NAME_SCALE_BLIT(Index8Gray, Index8Gray) { DeclareIndex8GrayLoadVars(SrcRead) DeclareIndex8GrayLoadVars(DstRead) - jint srcScan = pSrcInfo->scanStride; - jint dstScan = pDstInfo->scanStride; DeclareIndex8GrayStoreVars(DstWrite) InitIndex8GrayLoadVars(SrcRead, pSrcInfo); diff --git a/src/java.desktop/share/native/libawt/java2d/loops/UshortIndexed.c b/src/java.desktop/share/native/libawt/java2d/loops/UshortIndexed.c index 071459d29699..4832df50982a 100644 --- a/src/java.desktop/share/native/libawt/java2d/loops/UshortIndexed.c +++ b/src/java.desktop/share/native/libawt/java2d/loops/UshortIndexed.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, 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 @@ -196,8 +196,6 @@ void NAME_SCALE_BLIT(UshortIndexed, UshortIndexed) { DeclareUshortIndexedLoadVars(SrcRead) DeclareUshortIndexedLoadVars(DstRead) - jint srcScan = pSrcInfo->scanStride; - jint dstScan = pDstInfo->scanStride; DeclareUshortIndexedStoreVars(DstWrite) InitUshortIndexedLoadVars(SrcRead, pSrcInfo); diff --git a/src/java.desktop/share/native/libawt/java2d/pipe/ShapeSpanIterator.c b/src/java.desktop/share/native/libawt/java2d/pipe/ShapeSpanIterator.c index 5b34ac9fbaa6..eb1bc8f83350 100644 --- a/src/java.desktop/share/native/libawt/java2d/pipe/ShapeSpanIterator.c +++ b/src/java.desktop/share/native/libawt/java2d/pipe/ShapeSpanIterator.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -418,7 +418,6 @@ Java_sun_java2d_pipe_ShapeSpanIterator_addSegment jfloat x1, y1, x2, y2, x3, y3; jboolean oom = JNI_FALSE; pathData *pd; - int numpts = 0; pd = GetSpanData(env, sr, STATE_HAVE_RULE, STATE_HAVE_RULE); if (pd == NULL) { diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftmodule.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftmodule.h index d908ce76bd12..8a1fa3a301b9 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftmodule.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftmodule.h @@ -15,6 +15,7 @@ FT_USE_MODULE( FT_Driver_ClassRec, tt_driver_class ) FT_USE_MODULE( FT_Driver_ClassRec, t1_driver_class ) FT_USE_MODULE( FT_Driver_ClassRec, cff_driver_class ) FT_USE_MODULE( FT_Driver_ClassRec, t1cid_driver_class ) +// FT_USE_MODULE( FT_Driver_ClassRec, hvf_driver_class ) // FT_USE_MODULE( FT_Driver_ClassRec, pfr_driver_class ) // FT_USE_MODULE( FT_Driver_ClassRec, t42_driver_class ) // FT_USE_MODULE( FT_Driver_ClassRec, winfnt_driver_class ) diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h index a4e9c7f3e831..b74a3bc55787 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/config/ftoption.h @@ -334,6 +334,22 @@ FT_BEGIN_HEADER /* #define FT_CONFIG_OPTION_USE_BROTLI */ + /************************************************************************** + * + * HVF support. + * + * FreeType can use Apple's HVF (Hierarchical Variable Font) library + * to render glyphs from fonts containing 'hvgl' tables. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_HVF */ + + /************************************************************************** * * Glyph Postscript Names handling @@ -423,8 +439,10 @@ FT_BEGIN_HEADER /************************************************************************** * - * The size in bytes of the render pool used by the scan-line converter to - * do all of its work. + * The size in bytes of the stack render pool used by the scan-line + * converters. Use this option to limit the stack usage. The memory + * requirements are proportional to size and complexity of a given glyph. + * FreeType's rasterizers switch to dynamic allocations when necessary. */ #define FT_RENDER_POOL_SIZE 16384L @@ -651,6 +669,7 @@ FT_BEGIN_HEADER #define TT_CONFIG_CMAP_FORMAT_12 #define TT_CONFIG_CMAP_FORMAT_13 #define TT_CONFIG_CMAP_FORMAT_14 +#define TT_CONFIG_CMAP_FORMAT_15 /*************************************************************************/ @@ -756,6 +775,21 @@ FT_BEGIN_HEADER /* #define TT_CONFIG_OPTION_NO_BORING_EXPANSION */ + /************************************************************************** + * + * Define `TT_CONFIG_OPTION_VARC` if you want to include support for + * variable composite glyphs (the 'VARC' table). This is part of the + * 'boring' OpenType specification expansions. + * + * https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md + * + * Variable composites enable more efficient encoding of variable glyphs + * by allowing glyphs to be composed from other glyphs with variable + * transformations and axis value overrides. + */ +/* #define TT_CONFIG_OPTION_VARC */ + + /************************************************************************** * * Define `TT_CONFIG_OPTION_BDF` if you want to include support for an diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h b/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h index 68a9e0c6bd2c..0a330c7c3f66 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/freetype.h @@ -4134,7 +4134,7 @@ FT_BEGIN_HEADER * This function returns an error if the charmap is not part of the face * (i.e., if it is not listed in the `face->charmaps` table). * - * It also fails if an OpenType type~14 charmap is selected (which + * It also fails if an OpenType type 14 or~15 charmap is selected (which * doesn't map character codes to glyph indices at all). */ FT_EXPORT( FT_Error ) @@ -4700,7 +4700,7 @@ FT_BEGIN_HEADER * * @abstract: * The FreeType~2 interface to Unicode Variation Sequences (UVS), using - * the SFNT cmap format~14. + * the SFNT cmap formats 14 and~15. * * @description: * Many characters, especially for CJK scripts, have variant forms. They @@ -4730,9 +4730,10 @@ FT_BEGIN_HEADER * U+9089, you have to write the character sequence `U+9089 U+E0100`. * * Adobe and MS decided to support both standardized and ideographic VS - * with a new cmap subtable (format~14). It is an odd subtable because - * it is not a mapping of input code points to glyphs, but contains lists - * of all variations supported by the font. + * with a new cmap subtable (format~14, or format~15 for glyph indices + * above 65535). It is an odd subtable because it is not a mapping of + * input code points to glyphs, but contains lists of all variations + * supported by the font. * * A variation may be either 'default' or 'non-default' for a given font. * A default variation is the one you will get for that code point if you @@ -5168,8 +5169,8 @@ FT_BEGIN_HEADER * */ #define FREETYPE_MAJOR 2 -#define FREETYPE_MINOR 14 -#define FREETYPE_PATCH 3 +#define FREETYPE_MINOR 15 +#define FREETYPE_PATCH 0 /************************************************************************** diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h index 1fff76b20d91..61de54e48cbb 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftimage.h @@ -471,7 +471,7 @@ FT_BEGIN_HEADER /* */ -#define FT_CURVE_TAG( flag ) ( flag & 0x03 ) +#define FT_CURVE_TAG( flag ) ( ( flag & 0x01 ) ? 0x01 : ( flag & 0x03 ) ) /* see the `tags` field in `FT_Outline` for a description of the values */ #define FT_CURVE_TAG_ON 0x01 @@ -875,7 +875,7 @@ FT_BEGIN_HEADER */ typedef struct FT_Span_ { - unsigned short x; + short x; unsigned short len; unsigned char coverage; diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h b/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h index 7c1b1fd3c040..9010c9fc489a 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/ftmoderr.h @@ -172,6 +172,7 @@ FT_MODERRDEF( Winfonts, 0x1500, "Windows FON/FNT module" ) FT_MODERRDEF( GXvalid, 0x1600, "GX validation module" ) FT_MODERRDEF( Sdf, 0x1700, "Signed distance field raster module" ) + FT_MODERRDEF( HVF, 0x1800, "HVF module" ) #ifdef FT_MODERR_END_LIST diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h index 97ddcde65aa6..2f3ca05955a0 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/fttypes.h @@ -25,8 +25,6 @@ #include #include -#include - FT_BEGIN_HEADER diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h index 4c4943164a38..129366f38949 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftcalc.h @@ -77,6 +77,10 @@ FT_BEGIN_HEADER #endif /* FT_INT64 */ +#define ULABS( a ) ( a >= 0 ? (FT_ULong)a : 0UL - (FT_ULong)a ) +#define UABS( a ) ( a >= 0 ? (FT_UInt)a : 0U - (FT_UInt)a ) + + /************************************************************************** * * FT_MulDiv() and FT_MulFix() are declared in freetype.h. diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h index 62b9ec2f79c7..1baf5f385a84 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftdebug.h @@ -33,6 +33,7 @@ #ifdef FT_DEBUG_LOGGING #define DLG_STATIC +#define DLG_LOG_LEVEL dlg_level_trace #include #include diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h index a4db9c487b75..854798ad3c0e 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftmmtypes.h @@ -71,6 +71,13 @@ FT_BEGIN_HEADER FT_UInt regionCount; /* total number of regions defined */ GX_VarRegion varRegionList; + /* Cache of per-region scalars for the current normalized coordinates. */ + /* `regionScalars` holds `regionCount` values, `cachedCoords` the */ + /* `axisCount` coordinates they were computed for; both are NULL until */ + /* first use and recomputed whenever the coordinates change. */ + FT_Fixed* regionScalars; + FT_Fixed* cachedCoords; + } GX_ItemVarStoreRec, *GX_ItemVarStore; diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h index 4fa4991dd88c..f97262ffa951 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftobjs.h @@ -214,8 +214,8 @@ FT_BEGIN_HEADER FT_CMap_CharIndexFunc char_index; FT_CMap_CharNextFunc char_next; - /* Subsequent entries are special ones for format 14 -- the variant */ - /* selector subtable which behaves like no other */ + /* Subsequent entries are special ones for formats 14 and 15 -- */ + /* the variant selector subtables which behave like no other */ FT_CMap_CharVarIndexFunc char_var_index; FT_CMap_CharVarIsDefaultFunc char_var_default; diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h index 9c6406c82d8a..3b326627074d 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/ftserv.h @@ -173,6 +173,7 @@ FT_BEGIN_HEADER * FT_DEFINE_SERVICEDESCREC8 * FT_DEFINE_SERVICEDESCREC9 * FT_DEFINE_SERVICEDESCREC10 + * FT_DEFINE_SERVICEDESCREC11 * * @description: * Used to initialize an array of FT_ServiceDescRec structures. @@ -350,6 +351,34 @@ FT_BEGIN_HEADER { NULL, NULL } \ }; +#define FT_DEFINE_SERVICEDESCREC11( class_, \ + serv_id_1, serv_data_1, \ + serv_id_2, serv_data_2, \ + serv_id_3, serv_data_3, \ + serv_id_4, serv_data_4, \ + serv_id_5, serv_data_5, \ + serv_id_6, serv_data_6, \ + serv_id_7, serv_data_7, \ + serv_id_8, serv_data_8, \ + serv_id_9, serv_data_9, \ + serv_id_10, serv_data_10, \ + serv_id_11, serv_data_11 ) \ + static const FT_ServiceDescRec class_[] = \ + { \ + { serv_id_1, serv_data_1 }, \ + { serv_id_2, serv_data_2 }, \ + { serv_id_3, serv_data_3 }, \ + { serv_id_4, serv_data_4 }, \ + { serv_id_5, serv_data_5 }, \ + { serv_id_6, serv_data_6 }, \ + { serv_id_7, serv_data_7 }, \ + { serv_id_8, serv_data_8 }, \ + { serv_id_9, serv_data_9 }, \ + { serv_id_10, serv_data_10 }, \ + { serv_id_11, serv_data_11 }, \ + { NULL, NULL } \ + }; + /* * Parse a list of FT_ServiceDescRec descriptors and look for a specific diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h index 798896cd0c82..22291ef7cfe5 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/fttrace.h @@ -79,6 +79,7 @@ FT_TRACE_DEF( ttgxvar ) /* TrueType GX var handler (ttgxvar.c) */ FT_TRACE_DEF( ttinterp ) /* bytecode interpreter (ttinterp.c) */ FT_TRACE_DEF( ttobjs ) /* TT objects manager (ttobjs.c) */ FT_TRACE_DEF( ttpload ) /* TT data/program loader (ttpload.c) */ +FT_TRACE_DEF( ttvarc ) /* TT VARC handler (ttvarc.c) */ /* Type 1 driver components */ FT_TRACE_DEF( t1afm ) @@ -120,6 +121,11 @@ FT_TRACE_DEF( cidload ) FT_TRACE_DEF( cidobjs ) FT_TRACE_DEF( cidparse ) + /* HVF driver component */ +FT_TRACE_DEF( hvfdrv ) +FT_TRACE_DEF( hvfobjs ) +FT_TRACE_DEF( hvfload ) + /* Windows font component */ FT_TRACE_DEF( winfnt ) diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h index 770381da67a1..91a6f007aa52 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svfntfmt.h @@ -40,6 +40,7 @@ FT_BEGIN_HEADER #define FT_FONT_FORMAT_TYPE_42 "Type 42" #define FT_FONT_FORMAT_CID "CID Type 1" #define FT_FONT_FORMAT_CFF "CFF" +#define FT_FONT_FORMAT_HVF "HVF" #define FT_FONT_FORMAT_PFR "PFR" #define FT_FONT_FORMAT_WINFNT "Windows FNT" diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h index 14921304ebfc..d7ad8066b5ee 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/services/svttcmap.h @@ -52,7 +52,8 @@ FT_BEGIN_HEADER * table), 2~(high-byte mapping through table), 4~(segment mapping to * delta values), 6~(trimmed table mapping), 8~(mixed 16-bit and 32-bit * coverage), 10~(trimmed array), 12~(segmented coverage), 13~(last - * resort font), and 14 (Unicode Variation Sequences). + * resort font), 14~(Unicode Variation Sequences), and 15~(extended + * glyph repertoire Unicode Variation Sequences). */ typedef struct TT_CMapInfo_ { diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h b/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h index 65341a3a259e..ad45da39b994 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/internal/tttypes.h @@ -1130,11 +1130,29 @@ FT_BEGIN_HEADER * The font's horizontal header ('hhea' table). This field also * contains the associated horizontal metrics table ('hmtx'). * + * horz_metrics_count :: + * The number of horizontal metrics. This can be larger than the + * public `TT_HoriHeader.number_Of_HMetrics` field when the font uses + * the 'HHEA table (instead of 'hhea'). + * + * horz_metrics_is_extended :: + * A boolean which is set when the font uses 'HHEA' and 'HMTX' tables + * (instead of 'hhea' and 'hmtx'). + * * max_profile :: * The font's maximum profile table. Read on font opening. Note that * some maximum values cannot be taken directly from this table. We * thus define additional fields below to hold the computed maxima. * + * maxp_num_glyphs :: + * The glyph count from the font's maximum profile table. This can be + * larger than the public `TT_MaxProfile.numGlyphs` field when the font + * uses the 24-bit 'MAXP' table. + * + * is_extended_glyf :: + * A boolean which is set when the font uses the 'GLYF' and 'LOCA' + * tables (extending 'glyf' and 'loca', respectively). + * * vertical_info :: * A boolean which is set when the font file contains vertical metrics. * If not, the value of the 'vertical' field is undefined. @@ -1145,6 +1163,15 @@ FT_BEGIN_HEADER * IMPORTANT: The contents of this field is undefined if the * `vertical_info` field is unset. * + * vert_metrics_count :: + * The number of vertical metrics. This can be larger than the public + * `TT_VertHeader.number_Of_VMetrics` field when the font uses the + * 'VHEA' table (instead of 'vhea'). + * + * vert_metrics_is_extended :: + * A boolean which is set when the font uses the 'VHEA' and 'VMTX' + * tables (instead of 'vhea' and 'vmtx'). + * * num_names :: * The number of name records within this TrueType font. * @@ -1166,6 +1193,25 @@ FT_BEGIN_HEADER * cmap_size :: * The size in bytes of the `cmap_table` described above. * + * dmap_table :: + * Address of the face's 'DMAP' SFNT table in memory (it's an extracted + * frame). + * + * dmap_size :: + * The size in bytes of the `dmap_table` described above. + * + * dmap_charmaps :: + * The array of 'DMAP' charmaps. + * + * num_dmap_charmaps :: + * The number of elements in `dmap_charmaps`. + * + * dmap_results :: + * An array used while merging a dmap with its corresponding cmap. + * + * dmap_max_results :: + * The current size of `dmap_results`. + * * goto_table :: * A function called by each TrueType table loader to position a * stream's cursor to the start of a given table according to its tag. @@ -1209,6 +1255,13 @@ FT_BEGIN_HEADER * A pointer to the Metrics Variations service for this `TT_Face`'s * driver. * + * tt_varc :: + * A pointer for sharing the VARC services provided by this + * `TT_Face`'s driver. + * + * face_varc :: + * A pointer to handle VARC glyphs by this `TT_Face`'s driver. + * * psaux :: * A pointer to the PostScript Auxiliary service. * @@ -1408,6 +1461,26 @@ FT_BEGIN_HEADER * svg :: * A pointer to data related to the 'SVG' table. `NULL` if the table * is not available. + * + * gpos_table :: + * A pointer to the 'GPOS' table. `NULL` if the table is not + * available. + * + * gpos_lookups_kerning :: + * An array of GPOS kerning lookups. + * + * num_gpos_lookups_kerning :: + * The number of GPOS kerning lookups. + * + * varc :: + * A pointer to data related to the 'VARC' table. `NULL` if the table + * is not available. + * + * varc_context :: + * A context to manage recursion in the 'VARC' table. + * + * varc_loading_components :: + * Set if component checks for 'VARC' table handling can be skipped. */ typedef struct TT_FaceRec_ { @@ -1421,11 +1494,17 @@ FT_BEGIN_HEADER TT_Header header; /* TrueType header table */ TT_HoriHeader horizontal; /* TrueType horizontal header */ + FT_UInt32 horz_metrics_count; + FT_Bool horz_metrics_is_extended; TT_MaxProfile max_profile; + FT_UInt maxp_num_glyphs; + FT_Bool is_extended_glyf; FT_Bool vertical_info; TT_VertHeader vertical; /* TT Vertical header, if present */ + FT_UInt32 vert_metrics_count; + FT_Bool vert_metrics_is_extended; FT_UShort num_names; /* number of name records */ TT_NameTableRec name_table; /* name table */ @@ -1436,6 +1515,13 @@ FT_BEGIN_HEADER FT_Byte* cmap_table; /* extracted `cmap' table */ FT_ULong cmap_size; + FT_Byte* dmap_table; /* extracted 'DMAP' table */ + FT_ULong dmap_size; + FT_CMap* dmap_charmaps; + FT_UInt num_dmap_charmaps; + FT_UInt32* dmap_results; + FT_UInt32 dmap_max_results; + TT_Loader_GotoTableFunc goto_table; TT_Loader_StartGlyphFunc access_glyph_frame; @@ -1468,6 +1554,16 @@ FT_BEGIN_HEADER void* face_var; /* since 2.13.1 */ #endif +#ifdef TT_CONFIG_OPTION_VARC + /* a typeless pointer to the FT_Service_VARCRec table used to */ + /* share VARC handling from the `truetype' driver */ + void* tt_varc; /* since 2.15 */ + + /* a typeless pointer to the FT_Service_VARCRec table used to */ + /* handle VARC glyphs by this TT_Face's driver */ + void* face_varc; /* since 2.15 */ +#endif + /* a typeless pointer to the PostScript Aux service */ void* psaux; @@ -1553,7 +1649,7 @@ FT_BEGIN_HEADER FT_ULong horz_metrics_size; FT_ULong vert_metrics_size; - FT_ULong num_locations; /* up to 0xFFFF + 1 */ + FT_ULong num_locations; /* up to 0xFFFFFF + 1 */ FT_Byte* glyph_locations; FT_Byte* hdmx_table; @@ -1604,6 +1700,15 @@ FT_BEGIN_HEADER FT_UInt num_gpos_lookups_kerning; #endif +#ifdef TT_CONFIG_OPTION_VARC + /* since 2.15 */ + void* varc; + /* Active recursion context. */ + void* varc_context; + /* Whether to skip VARC check for components. */ + FT_Bool varc_loading_components; +#endif + } TT_FaceRec; diff --git a/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h b/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h index 3be3e2ff9055..7d431cea490b 100644 --- a/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h +++ b/src/java.desktop/share/native/libfreetype/include/freetype/tttags.h @@ -49,6 +49,7 @@ FT_BEGIN_HEADER #define TTAG_CPAL FT_MAKE_TAG( 'C', 'P', 'A', 'L' ) #define TTAG_cvar FT_MAKE_TAG( 'c', 'v', 'a', 'r' ) #define TTAG_cvt FT_MAKE_TAG( 'c', 'v', 't', ' ' ) +#define TTAG_DMAP FT_MAKE_TAG( 'D', 'M', 'A', 'P' ) #define TTAG_DSIG FT_MAKE_TAG( 'D', 'S', 'I', 'G' ) #define TTAG_EBDT FT_MAKE_TAG( 'E', 'B', 'D', 'T' ) #define TTAG_EBLC FT_MAKE_TAG( 'E', 'B', 'L', 'C' ) @@ -60,23 +61,31 @@ FT_BEGIN_HEADER #define TTAG_gasp FT_MAKE_TAG( 'g', 'a', 's', 'p' ) #define TTAG_GDEF FT_MAKE_TAG( 'G', 'D', 'E', 'F' ) #define TTAG_glyf FT_MAKE_TAG( 'g', 'l', 'y', 'f' ) +#define TTAG_GLYF FT_MAKE_TAG( 'G', 'L', 'Y', 'F' ) #define TTAG_GPOS FT_MAKE_TAG( 'G', 'P', 'O', 'S' ) #define TTAG_GSUB FT_MAKE_TAG( 'G', 'S', 'U', 'B' ) #define TTAG_gvar FT_MAKE_TAG( 'g', 'v', 'a', 'r' ) +#define TTAG_GVAR FT_MAKE_TAG( 'G', 'V', 'A', 'R' ) #define TTAG_HVAR FT_MAKE_TAG( 'H', 'V', 'A', 'R' ) #define TTAG_hdmx FT_MAKE_TAG( 'h', 'd', 'm', 'x' ) #define TTAG_head FT_MAKE_TAG( 'h', 'e', 'a', 'd' ) #define TTAG_hhea FT_MAKE_TAG( 'h', 'h', 'e', 'a' ) +#define TTAG_HHEA FT_MAKE_TAG( 'H', 'H', 'E', 'A' ) #define TTAG_hmtx FT_MAKE_TAG( 'h', 'm', 't', 'x' ) +#define TTAG_HMTX FT_MAKE_TAG( 'H', 'M', 'T', 'X' ) +#define TTAG_hvgl FT_MAKE_TAG( 'h', 'v', 'g', 'l' ) +#define TTAG_hvpm FT_MAKE_TAG( 'h', 'v', 'p', 'm' ) #define TTAG_JSTF FT_MAKE_TAG( 'J', 'S', 'T', 'F' ) #define TTAG_just FT_MAKE_TAG( 'j', 'u', 's', 't' ) #define TTAG_kern FT_MAKE_TAG( 'k', 'e', 'r', 'n' ) #define TTAG_lcar FT_MAKE_TAG( 'l', 'c', 'a', 'r' ) #define TTAG_loca FT_MAKE_TAG( 'l', 'o', 'c', 'a' ) +#define TTAG_LOCA FT_MAKE_TAG( 'L', 'O', 'C', 'A' ) #define TTAG_LTSH FT_MAKE_TAG( 'L', 'T', 'S', 'H' ) #define TTAG_LWFN FT_MAKE_TAG( 'L', 'W', 'F', 'N' ) #define TTAG_MATH FT_MAKE_TAG( 'M', 'A', 'T', 'H' ) #define TTAG_maxp FT_MAKE_TAG( 'm', 'a', 'x', 'p' ) +#define TTAG_MAXP FT_MAKE_TAG( 'M', 'A', 'X', 'P' ) #define TTAG_META FT_MAKE_TAG( 'M', 'E', 'T', 'A' ) #define TTAG_MMFX FT_MAKE_TAG( 'M', 'M', 'F', 'X' ) #define TTAG_MMSD FT_MAKE_TAG( 'M', 'M', 'S', 'D' ) @@ -104,7 +113,10 @@ FT_BEGIN_HEADER #define TTAG_typ1 FT_MAKE_TAG( 't', 'y', 'p', '1' ) #define TTAG_VDMX FT_MAKE_TAG( 'V', 'D', 'M', 'X' ) #define TTAG_vhea FT_MAKE_TAG( 'v', 'h', 'e', 'a' ) +#define TTAG_VHEA FT_MAKE_TAG( 'V', 'H', 'E', 'A' ) #define TTAG_vmtx FT_MAKE_TAG( 'v', 'm', 't', 'x' ) +#define TTAG_VMTX FT_MAKE_TAG( 'V', 'M', 'T', 'X' ) +#define TTAG_VARC FT_MAKE_TAG( 'V', 'A', 'R', 'C' ) #define TTAG_VVAR FT_MAKE_TAG( 'V', 'V', 'A', 'R' ) #define TTAG_wOFF FT_MAKE_TAG( 'w', 'O', 'F', 'F' ) #define TTAG_wOF2 FT_MAKE_TAG( 'w', 'O', 'F', '2' ) diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c index 73addf28eb42..3c97f91dd933 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/aflatin.c @@ -2783,8 +2783,8 @@ { do { - point->y += movement; - point = point->next; + point->y = ADD_LONG( point->y, movement ); + point = point->next; } while ( point != first_point ); } @@ -3739,7 +3739,7 @@ pos = ADD_LONG( high_min_y, adjustment_amount ); if ( adjust_below_top && is_top_tilde ) - pos += high_height; + pos = ADD_LONG( pos, high_height ); if ( pos % 64 == 0 && tilde_height < 3 * 64 ) { @@ -3892,7 +3892,7 @@ pos = SUB_LONG( low_max_y, adjustment_amount ); if ( adjust_above_bottom && is_bottom_tilde ) - pos -= low_height; + pos = SUB_LONG( pos, low_height ); if ( pos % 64 == 0 && tilde_height < 3 * 64 ) { diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c index 4d0755decb20..c9f5e0a8aab0 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afranges.c @@ -104,7 +104,8 @@ AF_UNIRANGE_REC( 0xFE7A, 0xFE7A ), AF_UNIRANGE_REC( 0xFE7C, 0xFE7C ), AF_UNIRANGE_REC( 0xFE7E, 0xFE7E ), - AF_UNIRANGE_REC( 0x10EFD, 0x10EFF ), + AF_UNIRANGE_REC( 0x10ECB, 0x10ECF ), + AF_UNIRANGE_REC( 0x10EF0, 0x10EFF ), AF_UNIRANGE_REC( 0, 0 ) }; @@ -118,7 +119,8 @@ const AF_Script_UniRangeRec af_armn_nonbase_uniranges[] = { - AF_UNIRANGE_REC( 0x0559, 0x055F ), + AF_UNIRANGE_REC( 0x0558, 0x055F ), + AF_UNIRANGE_REC( 0x058B, 0x058C ), AF_UNIRANGE_REC( 0, 0 ) }; @@ -156,7 +158,8 @@ const AF_Script_UniRangeRec af_beng_uniranges[] = { - AF_UNIRANGE_REC( 0x0980, 0x09FF ), /* Bengali */ + AF_UNIRANGE_REC( 0x0980, 0x09FF ), /* Bengali */ + AF_UNIRANGE_REC( 0x11DF0, 0x11DFF ), /* Bengali Supplement */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -168,6 +171,7 @@ AF_UNIRANGE_REC( 0x09CD, 0x09CD ), AF_UNIRANGE_REC( 0x09E2, 0x09E3 ), AF_UNIRANGE_REC( 0x09FE, 0x09FE ), + AF_UNIRANGE_REC( 0x11DF0, 0x11DF0 ), AF_UNIRANGE_REC( 0, 0 ) }; @@ -470,7 +474,7 @@ AF_UNIRANGE_REC( 0x0591, 0x05BF ), AF_UNIRANGE_REC( 0x05C1, 0x05C2 ), AF_UNIRANGE_REC( 0x05C4, 0x05C5 ), - AF_UNIRANGE_REC( 0x05C7, 0x05C7 ), + AF_UNIRANGE_REC( 0x05C7, 0x05C9 ), AF_UNIRANGE_REC( 0xFB1E, 0xFB1E ), AF_UNIRANGE_REC( 0, 0 ) }; @@ -586,7 +590,7 @@ AF_UNIRANGE_REC( 0xAB6A, 0xAB6F ), /* ... continued */ AF_UNIRANGE_REC( 0xFB00, 0xFB06 ), /* Alphab. Present. Forms (Latin Ligs) */ AF_UNIRANGE_REC( 0x1D400, 0x1D7FF ), /* Mathematical Alphanumeric Symbols */ - AF_UNIRANGE_REC( 0x1DF00, 0x1DFFF ), /* Latin Extended-G */ + AF_UNIRANGE_REC( 0x1DF00, 0x1DFCC ), /* Latin Extended-G */ AF_UNIRANGE_REC( 0, 0 ) }; @@ -643,7 +647,8 @@ AF_UNIRANGE_REC( 0xA7F8, 0xA7F9 ), /* more modifier letters */ AF_UNIRANGE_REC( 0xAB5C, 0xAB5F ), /* more modifier letters */ AF_UNIRANGE_REC( 0xAB69, 0xAB69 ), /* modifier letter small turned w */ - AF_UNIRANGE_REC( 0x10780, 0x107FB ), /* Latin Extended-F */ + AF_UNIRANGE_REC( 0x10780, 0x107BF ), /* Latin Extended-F */ + AF_UNIRANGE_REC( 0x1DFCD, 0x1DFFF ), /* Latin Extended-G (subset) */ AF_UNIRANGE_REC( 0, 0 ) }; diff --git a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c index 5c9e5376ad05..3c0ffe094735 100644 --- a/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c +++ b/src/java.desktop/share/native/libfreetype/src/autofit/afshaper.c @@ -45,12 +45,16 @@ * that actually do the mapping job. Please check the OpenType * specification for more details on features and lookups. * - * 2. Create glyph ID sets from the corresponding lookup sets. + * 2. Create glyph ID sets from the corresponding lookup sets. For + * default coverage, start with glyphs already assigned to the style + * and compute their substitution closure. * * 3. The glyph set corresponding to AF_COVERAGE_DEFAULT is computed - * with all lookups specific to the OpenType script activated. It - * relies on the order of AF_DEFINE_STYLE_CLASS entries so that - * special coverages (like `oldstyle figures') don't get overwritten. + * with all lookups specific to the OpenType script activated. Only + * reachable glyphs are added, since a lookup can be shared by several + * scripts. It relies on the order of AF_DEFINE_STYLE_CLASS entries + * so that special coverages (like `oldstyle figures') don't get + * overwritten. * */ @@ -198,14 +202,34 @@ count++; #endif - /* get output coverage of GSUB feature */ - hb( ot_layout_lookup_collect_glyphs )( face, - HB_OT_TAG_GSUB, - idx, - NULL, - NULL, - NULL, - gsub_glyphs ); + if ( style_class->coverage != AF_COVERAGE_DEFAULT ) + { + /* get output coverage of GSUB feature */ + hb( ot_layout_lookup_collect_glyphs )( face, + HB_OT_TAG_GSUB, + idx, + NULL, + NULL, + NULL, + gsub_glyphs ); + } + } + + if ( style_class->coverage == AF_COVERAGE_DEFAULT ) + { + FT_UInt i; + + + /* A script's lookups can also substitute glyphs of other scripts. */ + /* Seed the closure with this style's glyphs so that their */ + /* substitutes inherit the same style. */ + for ( i = 0; i < globals->glyph_count; i++ ) + if ( ( gstyles[i] & AF_STYLE_MASK ) == style_class->style ) + hb( set_add )( gsub_glyphs, i ); + + hb( ot_layout_lookups_substitute_closure )( face, + gsub_lookups, + gsub_glyphs ); } #ifdef FT_DEBUG_LEVEL_TRACE diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c b/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c index 4641ce27e829..4007a9314f08 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftbbox.c @@ -291,11 +291,10 @@ /* It is called with either q2 or q3 positive, which is necessary */ /* for the peak to exist and avoids undefined FT_MSB. */ - shift = 27 - FT_MSB( (FT_UInt32)( FT_ABS( q1 ) | - FT_ABS( q2 ) | - FT_ABS( q3 ) | - FT_ABS( q4 ) ) ); - + shift = 8 * sizeof ( FT_Pos ) - 5 - FT_MSB( ULABS( q1 ) | + ULABS( q2 ) | + ULABS( q3 ) | + ULABS( q4 ) ); if ( shift > 0 ) { /* upscaling too much just wastes time */ diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c b/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c index f88cbc11e636..1606cbfa0905 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftbitmap.c @@ -776,18 +776,12 @@ FT_Bitmap source_bitmap; const FT_Bitmap* source; - FT_Vector source_offset; - FT_Vector target_offset; - FT_Bool free_source_bitmap = 0; FT_Bool free_target_bitmap_on_error = 0; - FT_Pos source_llx, source_lly, source_urx, source_ury; - FT_Pos target_llx, target_lly, target_urx, target_ury; - FT_Pos final_llx, final_lly, final_urx, final_ury; + FT_BBox sbx, tbx, fbx; unsigned int final_rows, final_width; - long x, y; if ( !library || !target || !source_ || !atarget_offset ) @@ -811,110 +805,32 @@ if ( !( source_->width && source_->rows ) ) return FT_Err_Ok; /* nothing to do */ - /* assure integer pixel offsets */ - source_offset.x = FT_PIX_FLOOR( source_offset_.x ); - source_offset.y = FT_PIX_FLOOR( source_offset_.y ); - target_offset.x = FT_PIX_FLOOR( atarget_offset->x ); - target_offset.y = FT_PIX_FLOOR( atarget_offset->y ); + /* get source bitmap dimensions assuming integer offsets */ + sbx.xMin = ( source_offset_.x >> 6 ); + sbx.yMin = ( source_offset_.y >> 6 ) - source_->rows; + sbx.xMax = ( source_offset_.x >> 6 ) + source_->width; + sbx.yMax = ( source_offset_.y >> 6 ); - /* get source bitmap dimensions */ - source_llx = source_offset.x; - if ( FT_LONG_MIN + (FT_Pos)( source_->rows << 6 ) + 64 > source_offset.y ) - { - FT_TRACE5(( - "FT_Bitmap_Blend: y coordinate overflow in source bitmap\n" )); - return FT_THROW( Invalid_Argument ); - } - source_lly = source_offset.y - ( source_->rows << 6 ); + FT_TRACE5(( "FT_Bitmap_Blend:\n" )); + FT_TRACE5(( " source bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", + sbx.xMin, sbx.yMin, sbx.xMax, sbx.yMax, + source_->width, source_->rows )); - if ( FT_LONG_MAX - (FT_Pos)( source_->width << 6 ) - 64 < source_llx ) + /* sanity check */ + if ( sbx.xMin > sbx.xMax || sbx.yMin > sbx.yMax || + source_->width > 0x7FFFU || source_->rows > 0x7FFFU ) { - FT_TRACE5(( - "FT_Bitmap_Blend: x coordinate overflow in source bitmap\n" )); + FT_TRACE5(( "FT_Bitmap_Blend: source dimension overflow\n" )); return FT_THROW( Invalid_Argument ); } - source_urx = source_llx + ( source_->width << 6 ); - source_ury = source_offset.y; - /* get target bitmap dimensions */ - if ( target->width && target->rows ) - { - target_llx = target_offset.x; - if ( FT_LONG_MIN + (FT_Pos)( target->rows << 6 ) > target_offset.y ) - { - FT_TRACE5(( - "FT_Bitmap_Blend: y coordinate overflow in target bitmap\n" )); - return FT_THROW( Invalid_Argument ); - } - target_lly = target_offset.y - ( target->rows << 6 ); - - if ( FT_LONG_MAX - (FT_Pos)( target->width << 6 ) < target_llx ) - { - FT_TRACE5(( - "FT_Bitmap_Blend: x coordinate overflow in target bitmap\n" )); - return FT_THROW( Invalid_Argument ); - } - target_urx = target_llx + ( target->width << 6 ); - target_ury = target_offset.y; - } - else + if ( !target->width || !target->rows ) { - target_llx = FT_LONG_MAX; - target_lly = FT_LONG_MAX; - target_urx = FT_LONG_MIN; - target_ury = FT_LONG_MIN; - } - - /* compute final bitmap dimensions */ - final_llx = FT_MIN( source_llx, target_llx ); - final_lly = FT_MIN( source_lly, target_lly ); - final_urx = FT_MAX( source_urx, target_urx ); - final_ury = FT_MAX( source_ury, target_ury ); - - final_width = ( final_urx - final_llx ) >> 6; - final_rows = ( final_ury - final_lly ) >> 6; - -#ifdef FT_DEBUG_LEVEL_TRACE - FT_TRACE5(( "FT_Bitmap_Blend:\n" )); - FT_TRACE5(( " source bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", - source_llx / 64, source_lly / 64, - source_urx / 64, source_ury / 64, - source_->width, source_->rows )); - - if ( target->width && target->rows ) - FT_TRACE5(( " target bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", - target_llx / 64, target_lly / 64, - target_urx / 64, target_ury / 64, - target->width, target->rows )); - else FT_TRACE5(( " target bitmap: empty\n" )); - if ( final_width && final_rows ) - FT_TRACE5(( " final bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", - final_llx / 64, final_lly / 64, - final_urx / 64, final_ury / 64, - final_width, final_rows )); - else - FT_TRACE5(( " final bitmap: empty\n" )); -#endif /* FT_DEBUG_LEVEL_TRACE */ - - if ( !( final_width && final_rows ) ) - return FT_Err_Ok; /* nothing to do */ - - /* for blending, set offset vector of final bitmap */ - /* temporarily to (0,0) */ - source_llx -= final_llx; - source_lly -= final_lly; - - if ( target->width && target->rows ) - { - target_llx -= final_llx; - target_lly -= final_lly; - } + final_width = source_->width; + final_rows = source_->rows; - /* set up target bitmap */ - if ( target->pixel_mode == FT_PIXEL_MODE_NONE ) - { /* create new empty bitmap */ target->width = final_width; target->rows = final_rows; @@ -926,72 +842,116 @@ return error; free_target_bitmap_on_error = 1; + + fbx = sbx; } - else if ( target->width != final_width || - target->rows != final_rows ) + else { - /* adjust old bitmap to enlarged size */ - int pitch, new_pitch; + /* get target bitmap dimensions assuming integer offsets */ + tbx.xMin = ( atarget_offset->x >> 6 ); + tbx.yMin = ( atarget_offset->y >> 6 ) - target->rows; + tbx.xMax = ( atarget_offset->x >> 6 ) + target->width; + tbx.yMax = ( atarget_offset->y >> 6 ); - unsigned char* buffer = NULL; + FT_TRACE5(( " target bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", + tbx.xMin, tbx.yMin, tbx.xMax, tbx.yMax, + target->width, target->rows )); + /* sanity check */ + if ( tbx.xMin > tbx.xMax || tbx.yMin > tbx.yMax ) + { + FT_TRACE5(( "FT_Bitmap_Blend: targget dimension overflow\n" )); + return FT_THROW( Invalid_Argument ); + } - pitch = target->pitch; + /* compute final bitmap dimensions */ + fbx.xMin = FT_MIN( sbx.xMin, tbx.xMin ); + fbx.yMin = FT_MIN( sbx.yMin, tbx.yMin ); + fbx.xMax = FT_MAX( sbx.xMax, tbx.xMax ); + fbx.yMax = FT_MAX( sbx.yMax, tbx.yMax ); - if ( pitch < 0 ) - pitch = -pitch; + /* sanity check */ + if ( fbx.xMin < -0x10000 || fbx.xMax >= 0x10000 || + fbx.yMin < -0x10000 || fbx.yMax >= 0x10000 ) + { + FT_TRACE5(( "FT_Bitmap_Blend: final dimension overflow\n" )); + return FT_THROW( Invalid_Argument ); + } - new_pitch = (int)final_width * 4; + final_width = fbx.xMax - fbx.xMin; + final_rows = fbx.yMax - fbx.yMin; - /* TODO: provide an in-buffer solution for large bitmaps */ - /* to avoid allocation of a new buffer */ - if ( FT_ALLOC_MULT( buffer, final_rows, new_pitch ) ) - goto Error; + /* adjust target bitmap to enlarged size */ + if ( target->width < final_width || + target->rows < final_rows ) + { + int pitch, new_pitch; - /* copy data to new buffer */ - x = target_llx >> 6; - y = target_lly >> 6; + unsigned char* buffer = NULL; - /* the bitmap flow is from top to bottom, */ - /* but y is measured from bottom to top */ - if ( target->pitch < 0 ) - { - /* XXX */ - } - else - { - unsigned char* p = - target->buffer; - unsigned char* q = - buffer + - ( final_rows - y - target->rows ) * new_pitch + - x * 4; - unsigned char* limit_p = - p + pitch * (int)target->rows; + pitch = target->pitch; + + if ( pitch < 0 ) + pitch = -pitch; + + new_pitch = (int)final_width * 4; + + /* TODO: provide an in-buffer solution for large bitmaps */ + /* to avoid allocation of a new buffer */ + if ( FT_ALLOC_MULT( buffer, final_rows, new_pitch ) ) + goto Error; + + /* copy data to new buffer */ - while ( p < limit_p ) + /* the bitmap flow is from top to bottom, */ + /* but y is measured from bottom to top */ + if ( target->pitch < 0 ) { - FT_MEM_COPY( q, p, pitch ); + /* XXX */ + } + else + { + FT_Pos x = tbx.xMin - fbx.xMin; + FT_Pos y = tbx.yMin - fbx.yMin; + + unsigned char* p = + target->buffer; + unsigned char* q = + buffer + + ( final_rows - y - target->rows ) * new_pitch + + x * 4; + unsigned char* limit_p = + p + pitch * (int)target->rows; + - p += pitch; - q += new_pitch; + while ( p < limit_p ) + { + FT_MEM_COPY( q, p, pitch ); + + p += pitch; + q += new_pitch; + } } - } - FT_FREE( target->buffer ); + FT_FREE( target->buffer ); - target->width = final_width; - target->rows = final_rows; + target->width = final_width; + target->rows = final_rows; - if ( target->pitch < 0 ) - target->pitch = -new_pitch; - else - target->pitch = new_pitch; + if ( target->pitch < 0 ) + target->pitch = -new_pitch; + else + target->pitch = new_pitch; - target->buffer = buffer; + target->buffer = buffer; + } } + FT_TRACE5(( " final bitmap: (%ld, %ld) -- (%ld, %ld); %u x %u\n", + fbx.xMin, fbx.yMin, fbx.xMax, fbx.yMax, + final_width, final_rows )); + /* adjust source bitmap if necessary */ if ( source_->pixel_mode != FT_PIXEL_MODE_GRAY ) { @@ -1008,8 +968,6 @@ /* do blending; the code below returns pre-multiplied channels, */ /* similar to what FreeType gets from `CBDT' tables */ - x = source_llx >> 6; - y = source_lly >> 6; /* the bitmap flow is from top to bottom, */ /* but y is measured from bottom to top */ @@ -1019,6 +977,9 @@ } else { + FT_Pos x = sbx.xMin - fbx.xMin; + FT_Pos y = sbx.yMin - fbx.yMin; + unsigned char* p = source->buffer; unsigned char* q = @@ -1064,8 +1025,8 @@ } } - atarget_offset->x = final_llx; - atarget_offset->y = final_lly + ( final_rows << 6 ); + atarget_offset->x = fbx.xMin * 64; + atarget_offset->y = fbx.yMax * 64; Error: if ( error && free_target_bitmap_on_error ) diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c b/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c index d233dba3d6bf..c78d3b6da4b8 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftcalc.c @@ -714,9 +714,8 @@ FT_Matrix_Check( const FT_Matrix* matrix ) { FT_Fixed xx, xy, yx, yy; - FT_Fixed val; + FT_ULong val, abs_det, frob_sq; FT_Int shift; - FT_ULong temp1, temp2; if ( !matrix ) @@ -726,16 +725,14 @@ xy = matrix->xy; yx = matrix->yx; yy = matrix->yy; - val = FT_ABS( xx ) | FT_ABS( xy ) | FT_ABS( yx ) | FT_ABS( yy ); + val = ULABS( xx ) | ULABS( xy ) | ULABS( yx ) | ULABS( yy ); /* we only handle non-zero 32-bit values */ - if ( !val || val > 0x7FFFFFFFL ) + if ( !val || val > 0x7FFFFFFFUL ) return 0; - /* Scale matrix to avoid the temp1 overflow, which is */ - /* more stringent than avoiding the temp2 overflow. */ - - shift = FT_MSB( val ) - 12; + /* Scale matrix to avoid overflows */ + shift = FT_MSB( val ) - 4 * sizeof ( FT_ULong ) + 2; if ( shift > 0 ) { @@ -745,11 +742,11 @@ yy >>= shift; } - temp1 = 32U * (FT_ULong)FT_ABS( xx * yy - xy * yx ); - temp2 = (FT_ULong)( xx * xx ) + (FT_ULong)( xy * xy ) + - (FT_ULong)( yx * yx ) + (FT_ULong)( yy * yy ); + abs_det = ULABS( xx * yy - xy * yx ); + frob_sq = (FT_ULong)( xx * xx ) + (FT_ULong)( xy * xy ) + + (FT_ULong)( yx * yx ) + (FT_ULong)( yy * yy ); - if ( temp1 <= temp2 ) + if ( abs_det <= frob_sq / 32 ) return 0; return 1; @@ -966,7 +963,7 @@ FT_Int result; - if ( (FT_ULong)FT_ABS( in_x ) + (FT_ULong)FT_ABS( out_y ) <= 92681UL ) + if ( ULABS( in_x ) + ULABS( out_y ) <= 92681UL ) { z1.lo = (FT_UInt32)in_x * (FT_UInt32)out_y; z1.hi = (FT_UInt32)( (FT_Int32)z1.lo >> 31 ); /* sign-expansion */ @@ -974,7 +971,7 @@ else ft_multo64( (FT_UInt32)in_x, (FT_UInt32)out_y, &z1 ); - if ( (FT_ULong)FT_ABS( in_y ) + (FT_ULong)FT_ABS( out_x ) <= 92681UL ) + if ( ULABS( in_y ) + ULABS( out_x ) <= 92681UL ) { z2.lo = (FT_UInt32)in_y * (FT_UInt32)out_x; z2.hi = (FT_UInt32)( (FT_Int32)z2.lo >> 31 ); /* sign-expansion */ diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c b/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c index f9f64c40fec3..acefdf46fd9d 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftobjs.c @@ -42,6 +42,10 @@ #include #include +#ifdef TT_CONFIG_OPTION_VARC +#include +#endif + #include #ifdef FT_CONFIG_OPTION_MAC_FONTS @@ -503,8 +507,8 @@ pbox.xMin < -0x1000000 || pbox.xMax >= 0x1000000 || pbox.yMin < -0x1000000 || pbox.yMax >= 0x1000000 || ( slot->face && - ( width > 10 * slot->face->size->metrics.x_ppem || - height > 10 * slot->face->size->metrics.y_ppem ) ) ); + ( width > 16 * slot->face->size->metrics.x_ppem || + height > 16 * slot->face->size->metrics.y_ppem ) ) ); if ( ret ) FT_TRACE3(( "ft_glyphslot_preset_bitmap: [%ld %ld %ld %ld]\n", @@ -788,7 +792,7 @@ internal->transform_flags = 0; - if ( !matrix ) + if ( !matrix || !FT_Matrix_Check( matrix ) ) { internal->transform_matrix.xx = 0x10000L; internal->transform_matrix.xy = 0; @@ -1017,6 +1021,22 @@ } } +#ifdef TT_CONFIG_OPTION_VARC + /* Never auto-hint a VARC (variable composite) glyph: its components */ + /* are already loaded unhinted, and the auto-fitter cannot process */ + /* the assembled composite (it also re-enters variation-coordinate */ + /* setting). Use the native hinter / unhinted load instead. */ + if ( autohint && FT_IS_SFNT( face ) ) + { + FT_Service_VARC varc; + + + FT_FACE_FIND_SERVICE( face, varc, VARC ); + if ( varc && varc->has_glyph( face, glyph_index ) ) + autohint = FALSE; + } +#endif + if ( autohint ) { FT_AutoHinter_Interface hinting; @@ -1441,8 +1461,14 @@ { if ( cur[0]->encoding == FT_ENCODING_UNICODE ) { - face->charmap = cur[0]; - return FT_Err_Ok; + FT_Long format = FT_Get_CMap_Format( cur[0] ); + + + if ( format != 14 && format != 15 ) + { + face->charmap = cur[0]; + return FT_Err_Ok; + } } } @@ -1457,7 +1483,7 @@ * * @Description: * This function finds the variant selector charmap, if there is one. - * There can only be one (platform=0, specific=5, format=14). + * There can only be one (platform=0, specific=5, format=14 or 15). */ static FT_CharMap find_variant_selector_charmap( FT_Face face ) @@ -1480,9 +1506,14 @@ for ( cur = first; cur < end; cur++ ) { if ( cur[0]->platform_id == TT_PLATFORM_APPLE_UNICODE && - cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR && - FT_Get_CMap_Format( cur[0] ) == 14 ) - return cur[0]; + cur[0]->encoding_id == TT_APPLE_ID_VARIANT_SELECTOR ) + { + FT_Long format = FT_Get_CMap_Format( cur[0] ); + + + if ( format == 14 || format == 15 ) + return cur[0]; + } } return NULL; @@ -3771,11 +3802,16 @@ for ( ; cur < limit; cur++ ) { - if ( cur[0] == charmap && - FT_Get_CMap_Format ( charmap ) != 14 ) + if ( cur[0] == charmap ) { - face->charmap = cur[0]; - return FT_Err_Ok; + FT_Long format = FT_Get_CMap_Format( charmap ); + + + if ( format != 14 && format != 15 ) + { + face->charmap = cur[0]; + return FT_Err_Ok; + } } } @@ -4737,121 +4773,114 @@ FT_Error error = FT_Err_Ok; FT_Face face = slot->face; FT_Renderer renderer; + FT_ListNode node = NULL; - switch ( slot->format ) + /* try to render colored glyph layers as a special case */ + if ( slot->internal->load_flags & FT_LOAD_COLOR && + slot->format == FT_GLYPH_FORMAT_OUTLINE ) { - default: - if ( slot->internal->load_flags & FT_LOAD_COLOR ) - { - FT_LayerIterator iterator; + FT_LayerIterator iterator; - FT_UInt base_glyph = slot->glyph_index; + FT_UInt base_glyph = slot->glyph_index; - FT_Bool have_layers; - FT_UInt glyph_index; - FT_UInt color_index; + FT_Bool have_layers; + FT_UInt glyph_index; + FT_UInt color_index; - /* check whether we have colored glyph layers */ - iterator.p = NULL; - have_layers = FT_Get_Color_Glyph_Layer( face, - base_glyph, - &glyph_index, - &color_index, - &iterator ); - if ( have_layers ) + iterator.p = NULL; + have_layers = FT_Get_Color_Glyph_Layer( face, + base_glyph, + &glyph_index, + &color_index, + &iterator ); + if ( have_layers ) + { + error = FT_New_GlyphSlot( face, NULL ); + if ( !error ) { - error = FT_New_GlyphSlot( face, NULL ); - if ( !error ) - { - TT_Face ttface = (TT_Face)face; - SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; + TT_Face ttface = (TT_Face)face; + SFNT_Service sfnt = (SFNT_Service)ttface->sfnt; - do - { - FT_Int32 load_flags = slot->internal->load_flags; + do + { + FT_Int32 load_flags = slot->internal->load_flags; - /* disable the `FT_LOAD_COLOR' flag to avoid recursion */ - /* right here in this function */ - load_flags &= ~FT_LOAD_COLOR; + /* disable the `FT_LOAD_COLOR' flag to avoid recursion */ + /* right here in this function */ + load_flags &= ~FT_LOAD_COLOR; - /* render into the new `face->glyph' glyph slot */ - load_flags |= FT_LOAD_RENDER; + /* render into the new `face->glyph' glyph slot */ + load_flags |= FT_LOAD_RENDER | FT_LOAD_NO_BITMAP; - error = FT_Load_Glyph( face, glyph_index, load_flags ); - if ( error ) - break; - - /* blend new `face->glyph' into old `slot'; */ - /* at the first call, `slot' is still empty */ - error = sfnt->colr_blend( ttface, - color_index, - slot, - face->glyph ); - if ( error ) - break; - - } while ( FT_Get_Color_Glyph_Layer( face, - base_glyph, - &glyph_index, - &color_index, - &iterator ) ); + error = FT_Load_Glyph( face, glyph_index, load_flags ); + if ( error ) + break; - if ( !error ) - slot->format = FT_GLYPH_FORMAT_BITMAP; + /* blend new `face->glyph' into old `slot'; */ + /* at the first call, `slot' is still empty */ + error = sfnt->colr_blend( ttface, + color_index, + slot, + face->glyph ); + if ( error ) + break; - /* this call also restores `slot' as the glyph slot */ - FT_Done_GlyphSlot( face->glyph ); - } + } while ( FT_Get_Color_Glyph_Layer( face, + base_glyph, + &glyph_index, + &color_index, + &iterator ) ); if ( !error ) - return error; + slot->format = FT_GLYPH_FORMAT_BITMAP; - /* Failed to do the colored layer. Draw outline instead. */ - slot->format = FT_GLYPH_FORMAT_OUTLINE; + /* this call also restores `slot' as the glyph slot */ + FT_Done_GlyphSlot( face->glyph ); } - } - { - FT_ListNode node = NULL; + if ( !error ) + return error; + /* Failed to do the colored layer. Draw outline instead. */ + slot->format = FT_GLYPH_FORMAT_OUTLINE; + } + } - /* small shortcut for the very common case */ - if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) - { - renderer = library->cur_renderer; - node = library->renderers.head; - } - else - renderer = FT_Lookup_Renderer( library, slot->format, &node ); + /* small shortcut for the very common case */ + if ( slot->format == FT_GLYPH_FORMAT_OUTLINE ) + { + renderer = library->cur_renderer; + node = library->renderers.head; + } + else + renderer = FT_Lookup_Renderer( library, slot->format, &node ); - error = FT_ERR( Cannot_Render_Glyph ); - while ( renderer ) - { - error = renderer->render( renderer, slot, render_mode, NULL ); - if ( !error || - FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) - break; - - /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ - /* is unsupported by the current renderer for this glyph image */ - /* format. */ - - /* now, look for another renderer that supports the same */ - /* format. */ - renderer = FT_Lookup_Renderer( library, slot->format, &node ); - } + error = FT_ERR( Cannot_Render_Glyph ); + while ( renderer ) + { + error = renderer->render( renderer, slot, render_mode, NULL ); + if ( !error || + FT_ERR_NEQ( error, Cannot_Render_Glyph ) ) + break; - /* it is not an error if we cannot render a bitmap glyph */ - if ( FT_ERR_EQ( error, Cannot_Render_Glyph ) && - slot->format == FT_GLYPH_FORMAT_BITMAP ) - error = FT_Err_Ok; - } + /* `FT_Err_Cannot_Render_Glyph` is returned if the render mode */ + /* is unsupported by the current renderer for this glyph image */ + /* format. */ + + /* now, look for another renderer that supports the same */ + /* format. */ + renderer = FT_Lookup_Renderer( library, slot->format, &node ); } + /* it is not an error if we cannot render a bitmap glyph */ + if ( FT_ERR_EQ( error, Cannot_Render_Glyph ) && + slot->format == FT_GLYPH_FORMAT_BITMAP ) + error = FT_Err_Ok; + #ifdef FT_DEBUG_LEVEL_TRACE #undef FT_COMPONENT diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c b/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c index a0a1549adaaa..b37b53312fcd 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftoutln.c @@ -102,15 +102,14 @@ tags = outline->tags + first; tag = FT_CURVE_TAG( tags[0] ); - /* A contour cannot start with a cubic control point! */ - if ( tag == FT_CURVE_TAG_CUBIC ) - goto Invalid_Outline; - /* check first point to determine origin */ - if ( tag == FT_CURVE_TAG_CONIC ) + if ( tag != FT_CURVE_TAG_ON ) { - /* first point is conic control. Yes, this happens. */ - if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + FT_Int last_tag = FT_CURVE_TAG( outline->tags[last] ); + + + /* first point is a control point. Yes, this happens. */ + if ( last_tag == FT_CURVE_TAG_ON ) { /* start at last point if it is on the curve */ v_start = v_last; @@ -118,13 +117,16 @@ } else { - /* if both first and last points are conic, */ - /* start at their middle and record its position */ - /* for closure */ + if ( last_tag != tag ) + goto Invalid_Outline; + + /* if both first and last points are controls, */ + /* start at their middle and record its position */ + /* for closure */ v_start.x = ( v_start.x + v_last.x ) / 2; v_start.y = ( v_start.y + v_last.y ) / 2; - /* v_last = v_start; */ + /* v_last = v_start; */ } point--; tags--; @@ -242,11 +244,24 @@ if ( point <= limit ) { FT_Vector vec; + FT_Vector v_middle; + tag = FT_CURVE_TAG( tags[0] ); + vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); + if ( tag == FT_CURVE_TAG_CUBIC ) + { + v_middle.x = ( vec2.x + vec.x ) / 2; + v_middle.y = ( vec2.y + vec.y ) / 2; + + vec = v_middle; + } + else if ( tag != FT_CURVE_TAG_ON ) + goto Invalid_Outline; + FT_TRACE5(( " cubic to (%.2f, %.2f)" " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", (double)vec.x / 64, @@ -258,6 +273,12 @@ error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); if ( error ) goto Exit; + + if ( tag == FT_CURVE_TAG_CUBIC ) + { + point--; + tags--; + } continue; } @@ -554,11 +575,15 @@ last = -1; for ( n = 0; n < outline->n_contours; n++ ) { - /* keep the first contour point as is and swap points around it */ - /* to guarantee that the cubic arches stay valid after reverse */ - first = last + 2; + first = last + 1; last = outline->contours[n]; + /* Keep the first point unless it is a cubic control. In that */ + /* case, reverse the entire contour to preserve control pairs, */ + /* including contours with no explicit on-curve points. */ + if ( FT_CURVE_TAG( outline->tags[first] ) != FT_CURVE_TAG_CUBIC ) + first++; + /* reverse point table */ { FT_Vector* p = outline->points + first; @@ -1050,12 +1075,17 @@ FT_EXPORT_DEF( FT_Orientation ) FT_Outline_Get_Orientation( FT_Outline* outline ) { + FT_Vector* points; + FT_Int c, n, first, last; + +#ifdef FT_INT64 + FT_Int64 area = 0; +#else FT_BBox cbox = { 0, 0, 0, 0 }; FT_Int xshift, yshift; - FT_Vector* points; FT_Vector v_prev, v_cur; - FT_Int c, n, first, last; FT_Pos area = 0; +#endif if ( !outline || outline->n_points <= 0 ) @@ -1066,6 +1096,42 @@ /* cubic or quadratic curves, this test deals with the polygon */ /* only that is spanned up by the control points. */ + points = outline->points; + +#ifdef FT_INT64 + + /* Single-pass shoelace. The 64-bit accumulator removes the need */ + /* for the coordinate shift pre-pass (and its `FT_Outline_Get_CBox` */ + /* traversal) that the 32-bit variant below uses. */ + last = -1; + for ( c = 0; c < outline->n_contours; c++ ) + { + FT_Pos prev_x, prev_y; + + + first = last + 1; + last = outline->contours[c]; + + prev_x = points[last].x; + prev_y = points[last].y; + + for ( n = first; n <= last; n++ ) + { + FT_Pos cur_x = points[n].x; + FT_Pos cur_y = points[n].y; + + + area = ADD_INT64( area, + MUL_INT64( SUB_INT64( cur_y, prev_y ), + ADD_INT64( cur_x, prev_x ) ) ); + + prev_x = cur_x; + prev_y = cur_y; + } + } + +#else /* !FT_INT64 */ + FT_Outline_Get_CBox( outline, &cbox ); /* Handle collapsed outlines to avoid undefined FT_MSB. */ @@ -1084,8 +1150,6 @@ yshift = FT_MSB( (FT_UInt32)( cbox.yMax - cbox.yMin ) ) - 14; yshift = FT_MAX( yshift, 0 ); - points = outline->points; - last = -1; for ( c = 0; c < outline->n_contours; c++ ) { @@ -1108,6 +1172,8 @@ } } +#endif /* FT_INT64 */ + if ( area > 0 ) return FT_ORIENTATION_POSTSCRIPT; else if ( area < 0 ) diff --git a/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c b/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c index e599ecaf46f5..cc93265b0ba2 100644 --- a/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c +++ b/src/java.desktop/share/native/libfreetype/src/base/ftstroke.c @@ -656,12 +656,11 @@ FT_UInt num_contours = 0; FT_UInt count = border->num_points; - FT_Vector* point = border->points; FT_Byte* tags = border->tags; FT_Int in_contour = 0; - for ( ; count > 0; count--, num_points++, point++, tags++ ) + for ( ; count > 0; count--, num_points++, tags++ ) { if ( tags[0] & FT_STROKE_TAG_BEGIN ) { @@ -1875,6 +1874,10 @@ goto Exit; } + /* don't try to end the path if no segments have been generated */ + if ( stroker->first_point ) + goto Exit; + if ( stroker->subpath_open ) { FT_StrokeBorder right = stroker->borders; @@ -2095,15 +2098,14 @@ tags = outline->tags + first; tag = FT_CURVE_TAG( tags[0] ); - /* A contour cannot start with a cubic control point! */ - if ( tag == FT_CURVE_TAG_CUBIC ) - goto Invalid_Outline; - /* check first point to determine origin */ - if ( tag == FT_CURVE_TAG_CONIC ) + if ( tag != FT_CURVE_TAG_ON ) { - /* First point is conic control. Yes, this happens. */ - if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + FT_Int last_tag = FT_CURVE_TAG( outline->tags[last] ); + + + /* First point is a control point. Yes, this happens. */ + if ( last_tag == FT_CURVE_TAG_ON ) { /* start at last point if it is on the curve */ v_start = v_last; @@ -2111,8 +2113,11 @@ } else { - /* if both first and last points are conic, */ - /* start at their middle */ + if ( last_tag != tag ) + goto Invalid_Outline; + + /* if both first and last points are controls, */ + /* start at their middle */ v_start.x = ( v_start.x + v_last.x ) / 2; v_start.y = ( v_start.y + v_last.y ) / 2; } @@ -2206,13 +2211,31 @@ if ( point <= limit ) { FT_Vector vec; + FT_Vector v_middle; + tag = FT_CURVE_TAG( tags[0] ); vec = point[0]; + if ( tag == FT_CURVE_TAG_CUBIC ) + { + v_middle.x = ( vec2.x + vec.x ) / 2; + v_middle.y = ( vec2.y + vec.y ) / 2; + + vec = v_middle; + } + else if ( tag != FT_CURVE_TAG_ON ) + goto Invalid_Outline; + error = FT_Stroker_CubicTo( stroker, &vec1, &vec2, &vec ); if ( error ) goto Exit; + + if ( tag == FT_CURVE_TAG_CUBIC ) + { + point--; + tags--; + } continue; } @@ -2226,13 +2249,9 @@ if ( error ) goto Exit; - /* don't try to end the path if no segments have been generated */ - if ( !stroker->first_point ) - { - error = FT_Stroker_EndSubPath( stroker ); - if ( error ) - goto Exit; - } + error = FT_Stroker_EndSubPath( stroker ); + if ( error ) + goto Exit; } return FT_Err_Ok; diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c index 18c7b879048b..935548ea647f 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffdrivr.c @@ -40,6 +40,10 @@ #include #endif +#ifdef TT_CONFIG_OPTION_VARC +#include +#endif + #include "cfferrs.h" #include @@ -1085,6 +1089,111 @@ #endif +#ifdef TT_CONFIG_OPTION_VARC + + /* + * VARC SERVICE + * + * The implementation belongs to the `truetype' module. The CFF + * driver only forwards calls for OpenType/CFF faces, in the same way + * that it forwards variation-font operations. + */ + + FT_CALLBACK_DEF( FT_Error ) + cff_varc_init_axes( FT_Face face, + FT_UInt axis_count ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_VARC varc = (FT_Service_VARC)cffface->tt_varc; + + + return varc && varc->init_axes + ? varc->init_axes( face, axis_count ) + : FT_THROW( Missing_Module ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_varc_load( FT_Face face, + FT_Stream stream ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_VARC varc = (FT_Service_VARC)cffface->tt_varc; + + + return varc ? varc->load( face, stream ) + : FT_THROW( Missing_Module ); + } + + + FT_CALLBACK_DEF( void ) + cff_varc_done( FT_Face face ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_VARC varc = (FT_Service_VARC)cffface->tt_varc; + + + if ( varc ) + varc->done( face ); + } + + + FT_CALLBACK_DEF( FT_Bool ) + cff_varc_has_glyph( FT_Face face, + FT_UInt glyph_index ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_VARC varc = (FT_Service_VARC)cffface->tt_varc; + + + return FT_BOOL( varc && varc->has_glyph( face, glyph_index ) ); + } + + + FT_CALLBACK_DEF( FT_Error ) + cff_varc_load_glyph( FT_Face face, + FT_GlyphSlot glyph_slot, + FT_UInt glyph_index, + FT_Int32 load_flags ) + { + CFF_Face cffface = (CFF_Face)face; + FT_Service_VARC varc = (FT_Service_VARC)cffface->tt_varc; + CFF_Font cff = (CFF_Font)cffface->extra.data; + + FT_Error error; + + + if ( !varc ) + return FT_THROW( Missing_Module ); + + if ( !FT_HAS_MULTIPLE_MASTERS( face ) && + cff && + cff->cff2 && + cff->vstore.axisCount ) + { + error = varc->init_axes( face, cff->vstore.axisCount ); + if ( error ) + return error; + } + + return varc->load_glyph( face, glyph_slot, + glyph_index, load_flags ); + } + + + FT_DEFINE_SERVICE_VARCREC( + cff_service_varc, + + cff_varc_init_axes, + cff_varc_load, + cff_varc_done, + cff_varc_has_glyph, + cff_varc_load_glyph + ) + +#endif /* TT_CONFIG_OPTION_VARC */ + + /* * CFFLOAD SERVICE * @@ -1113,7 +1222,24 @@ /*************************************************************************/ /*************************************************************************/ -#if defined TT_CONFIG_OPTION_GX_VAR_SUPPORT +#if defined( TT_CONFIG_OPTION_GX_VAR_SUPPORT ) && \ + defined( TT_CONFIG_OPTION_VARC ) + FT_DEFINE_SERVICEDESCREC11( + cff_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, + FT_SERVICE_ID_MULTI_MASTERS, &cff_service_multi_masters, + FT_SERVICE_ID_METRICS_VARIATIONS, &cff_service_metrics_variations, + FT_SERVICE_ID_VARC, &cff_service_varc, + FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cff_service_ps_name, + FT_SERVICE_ID_GLYPH_DICT, &cff_service_glyph_dict, + FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info, + FT_SERVICE_ID_CID, &cff_service_cid_info, + FT_SERVICE_ID_PROPERTIES, &cff_service_properties, + FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load + ) +#elif defined( TT_CONFIG_OPTION_GX_VAR_SUPPORT ) FT_DEFINE_SERVICEDESCREC10( cff_services, @@ -1128,6 +1254,20 @@ FT_SERVICE_ID_PROPERTIES, &cff_service_properties, FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load ) +#elif defined( TT_CONFIG_OPTION_VARC ) + FT_DEFINE_SERVICEDESCREC9( + cff_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_CFF, + FT_SERVICE_ID_VARC, &cff_service_varc, + FT_SERVICE_ID_POSTSCRIPT_INFO, &cff_service_ps_info, + FT_SERVICE_ID_POSTSCRIPT_FONT_NAME, &cff_service_ps_name, + FT_SERVICE_ID_GLYPH_DICT, &cff_service_glyph_dict, + FT_SERVICE_ID_TT_CMAP, &cff_service_get_cmap_info, + FT_SERVICE_ID_CID, &cff_service_cid_info, + FT_SERVICE_ID_PROPERTIES, &cff_service_properties, + FT_SERVICE_ID_CFF_LOAD, &cff_service_cff_load + ) #else FT_DEFINE_SERVICEDESCREC8( cff_services, diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c index 0c986930cee6..331c681b8ae2 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffgload.c @@ -24,6 +24,10 @@ #include #include +#ifdef TT_CONFIG_OPTION_VARC +#include +#endif + #include "cffload.h" #include "cffgload.h" @@ -235,7 +239,7 @@ return FT_THROW( Invalid_Argument ); } } - else if ( glyph_index >= cff->num_glyphs ) + else if ( glyph_index >= (FT_ULong)face->root.num_glyphs ) return FT_THROW( Invalid_Argument ); #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS @@ -408,6 +412,76 @@ #endif /* FT_CONFIG_OPTION_SVG */ +#ifdef TT_CONFIG_OPTION_VARC + + /* check for VARC glyphs */ + { + FT_Service_VARC varc = (FT_Service_VARC)face->face_varc; + + + if ( face->varc && + varc && + varc->has_glyph( (FT_Face)face, glyph_index ) ) + { + FT_TRACE3(( "Loading VARC glyph\n" )); + + error = varc->load_glyph( (FT_Face)face, + (FT_GlyphSlot)glyph, + glyph_index, + load_flags ); + if ( !error ) + { + SFNT_Service sfnt = (SFNT_Service)face->sfnt; + + FT_Short sb; + FT_UShort advanceX = 0; + FT_UShort advanceY = 0; + FT_BBox bbox; + + + FT_TRACE3(( "Successfully loaded VARC glyph\n" )); + + /* The outline comes from the VARC table, so the advance and */ + /* metrics must be supplied here (`get_metrics` applies */ + /* HVAR/VVAR). */ + sfnt->get_metrics( face, FALSE, glyph_index, &sb, &advanceX ); + sfnt->get_metrics( face, TRUE, glyph_index, &sb, &advanceY ); + + glyph->root.linearHoriAdvance = advanceX; + glyph->root.linearVertAdvance = advanceY; + + FT_Outline_Get_CBox( &glyph->root.outline, &bbox ); + glyph->root.metrics.horiBearingX = bbox.xMin; + glyph->root.metrics.horiBearingY = bbox.yMax; + glyph->root.metrics.width = SUB_LONG( bbox.xMax, bbox.xMin ); + glyph->root.metrics.height = SUB_LONG( bbox.yMax, bbox.yMin ); + + if ( ( load_flags & FT_LOAD_NO_SCALE ) || !size ) + { + glyph->root.metrics.horiAdvance = advanceX; + glyph->root.metrics.vertAdvance = advanceY; + } + else + { + glyph->root.metrics.horiAdvance = + FT_MulFix( advanceX, size->root.metrics.x_scale ); + glyph->root.metrics.vertAdvance = + FT_MulFix( advanceY, size->root.metrics.y_scale ); + } + + return FT_Err_Ok; + } + + FT_TRACE3(( "Failed to load VARC glyph, falling back to CFF\n" )); + } + } + +#endif /* TT_CONFIG_OPTION_VARC */ + + /* A VARC-only glyph has no CFF2 fallback CharString. */ + if ( glyph_index >= cff->num_glyphs ) + return FT_THROW( Invalid_Argument ); + /* top-level code ensures that FT_LOAD_NO_HINTING is set */ /* if FT_LOAD_NO_SCALE is active */ hinting = FT_BOOL( ( load_flags & FT_LOAD_NO_HINTING ) == 0 ); diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffload.c b/src/java.desktop/share/native/libfreetype/src/cff/cffload.c index 9d067cfeeb83..cfd5317ff52a 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffload.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffload.c @@ -634,6 +634,12 @@ if ( error ) goto Exit; + if ( !bytes ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + if ( !FT_QALLOC( name, byte_len + 1 ) ) { FT_MEM_COPY( name, bytes, byte_len ); diff --git a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c index c6ba35e27344..8efdd109f95c 100644 --- a/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/cff/cffobjs.c @@ -624,7 +624,13 @@ /* Note that this is only necessary for pure CFF and CEF fonts; */ /* SFNT based fonts use the `name' table instead. */ - cffface->num_glyphs = (FT_Long)cff->num_glyphs; + /* VARC can define glyphs beyond the CFF2 CharStrings INDEX. */ +#ifdef TT_CONFIG_OPTION_VARC + if ( !cff2 || + !face->varc || + cff->num_glyphs > face->max_profile.numGlyphs ) +#endif + cffface->num_glyphs = (FT_Long)cff->num_glyphs; dict = &cff->top_font.font_dict; diff --git a/src/java.desktop/share/native/libfreetype/src/cid/cidload.c b/src/java.desktop/share/native/libfreetype/src/cid/cidload.c index 1a0e6b1561e0..170ae2d1c7d2 100644 --- a/src/java.desktop/share/native/libfreetype/src/cid/cidload.c +++ b/src/java.desktop/share/native/libfreetype/src/cid/cidload.c @@ -512,12 +512,14 @@ CID_FaceInfo cid = &face->cid; FT_Memory memory = face->root.memory; FT_Stream stream = face->cid_stream; + PSAux_Service psaux = (PSAux_Service)face->psaux; FT_Error error; + FT_UInt n; CID_Subrs subr; FT_UInt max_offsets = 0; - FT_ULong* offsets = NULL; - PSAux_Service psaux = (PSAux_Service)face->psaux; + FT_ULong* offsets = NULL; + FT_ULong cum_len = 0; if ( FT_NEW_ARRAY( face->subrs, cid->num_dicts ) ) @@ -584,6 +586,14 @@ /* now, compute the size of subrs charstrings, */ /* allocate, and read them */ data_len = offsets[num_subrs] - offsets[0]; + cum_len += data_len; + + if ( cum_len / 4 > stream->size ) + { + FT_ERROR(( "cid_read_subrs: excessive overlaps\n" )); + error = FT_THROW( Invalid_File_Format ); + goto Fail; + } if ( FT_QNEW_ARRAY( subr->code, num_subrs + 1 ) || FT_QALLOC( subr->code[0], data_len ) ) diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c b/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c index 7e3475e6f589..bb8efc8156fe 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psintrp.c @@ -415,7 +415,7 @@ /* Blend numOperands on the stack, */ /* store results into the first numBlends values, */ /* then pop remaining arguments. */ - static void + static FT_Error cf2_doBlend( const CFF_Blend blend, CF2_Stack opStack, CF2_UInt numBlends ) @@ -423,10 +423,19 @@ CF2_UInt delta; CF2_UInt base; CF2_UInt i, j; - CF2_UInt numOperands = (CF2_UInt)( numBlends * blend->lenBV ); + CF2_UInt numOperands; + CF2_UInt count = cf2_stack_count( opStack ); + + + if ( blend->lenBV == 0 || + numBlends > count / blend->lenBV ) + return FT_THROW( Stack_Underflow ); + numOperands = numBlends * blend->lenBV; /* cannot overflow here */ + if ( numOperands > count ) + return FT_THROW( Stack_Underflow ); - base = cf2_stack_count( opStack ) - numOperands; + base = count - numOperands; delta = base + numBlends; FT_TRACE6(( " (" )); @@ -455,6 +464,8 @@ /* leave only `numBlends' results on stack */ cf2_stack_pop( opStack, numOperands - numBlends ); + + return FT_Err_Ok; } @@ -769,13 +780,10 @@ /* do the blend */ numBlends = (FT_UInt)cf2_stack_popInt( opStack ); - if ( numBlends > stackSize ) - { - lastError = FT_THROW( Invalid_Glyph_Format ); - goto exit; - } - cf2_doBlend( &font->blend, opStack, numBlends ); + lastError = cf2_doBlend( &font->blend, opStack, numBlends ); + if ( lastError ) + goto exit; font->blend.usedBV = TRUE; } @@ -985,8 +993,8 @@ FT_TRACE4(( "%s", op1 == cf2_cmdCALLGSUBR ? " callgsubr" : " callsubr" )); - if ( ( !font->isT1 && charstringIndex > CF2_MAX_SUBR ) || - ( font->isT1 && charstringIndex > T1_MAX_SUBRS_CALLS ) ) + if ( ( !font->isT1 && charstringIndex >= CF2_MAX_SUBR ) || + ( font->isT1 && charstringIndex >= T1_MAX_SUBRS_CALLS ) ) { /* max subr plus one for charstring */ lastError = FT_THROW( Invalid_Glyph_Format ); diff --git a/src/java.desktop/share/native/libfreetype/src/psaux/psstack.c b/src/java.desktop/share/native/libfreetype/src/psaux/psstack.c index 797486588a34..1360ba30dab7 100644 --- a/src/java.desktop/share/native/libfreetype/src/psaux/psstack.c +++ b/src/java.desktop/share/native/libfreetype/src/psaux/psstack.c @@ -211,7 +211,7 @@ CF2_UInt idx, CF2_Fixed val ) { - if ( idx > cf2_stack_count( stack ) ) + if ( idx >= cf2_stack_count( stack ) ) { CF2_SET_ERROR( stack->error, Stack_Overflow ); return; @@ -245,6 +245,7 @@ CF2_StackNumber last = { { 0 }, CF2_NumberInt }; CF2_Int start_idx, idx, i; + CF2_Int offset; if ( count < 2 ) @@ -256,6 +257,8 @@ return; } + offset = (CF2_Int)cf2_stack_count( stack ) - count; + /* before C99 it is implementation-defined whether */ /* the result of `%' is negative if the first operand */ /* is negative */ @@ -303,7 +306,7 @@ { start_idx++; idx = start_idx; - last = stack->buffer[idx]; + last = stack->buffer[idx + offset]; } idx += shift; @@ -312,9 +315,9 @@ else if ( idx < 0 ) idx += count; - tmp = stack->buffer[idx]; - stack->buffer[idx] = last; - last = tmp; + tmp = stack->buffer[idx + offset]; + stack->buffer[idx + offset] = last; + last = tmp; } } diff --git a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c index 4165800a1aac..e0121f6ee1ac 100644 --- a/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c +++ b/src/java.desktop/share/native/libfreetype/src/raster/ftraster.c @@ -1622,15 +1622,14 @@ tag = FT_CURVE_TAG( tags[0] ); - /* A contour cannot start with a cubic control point! */ - if ( tag == FT_CURVE_TAG_CUBIC ) - goto Invalid_Outline; - /* check first point to determine origin */ - if ( tag == FT_CURVE_TAG_CONIC ) + if ( tag != FT_CURVE_TAG_ON ) { - /* first point is conic control. Yes, this happens. */ - if ( FT_CURVE_TAG( ras.outline.tags[last] ) == FT_CURVE_TAG_ON ) + UInt last_tag = FT_CURVE_TAG( ras.outline.tags[last] ); + + + /* first point is a control point. Yes, this happens. */ + if ( last_tag == FT_CURVE_TAG_ON ) { /* start at last point if it is on the curve */ v_start = v_last; @@ -1638,9 +1637,12 @@ } else { - /* if both first and last points are conic, */ - /* start at their middle and record its position */ - /* for closure */ + if ( last_tag != tag ) + goto Invalid_Outline; + + /* if both first and last points are controls, */ + /* start at their middle and record its position */ + /* for closure */ v_start.x = ( v_start.x + v_last.x ) / 2; v_start.y = ( v_start.y + v_last.y ) / 2; @@ -1755,14 +1757,30 @@ if ( point <= limit ) { + tag = FT_CURVE_TAG( tags[0] ); + x3 = SCALED( point[0].x ); y3 = SCALED( point[0].y ); if ( flipped ) SWAP_( x3, y3 ); + if ( tag == FT_CURVE_TAG_CUBIC ) + { + x3 = ( x2 + x3 ) / 2; + y3 = ( y2 + y3 ) / 2; + } + else if ( tag != FT_CURVE_TAG_ON ) + goto Invalid_Outline; + if ( Cubic_To( RAS_VARS x1, y1, x2, y2, x3, y3 ) ) goto Fail; + + if ( tag == FT_CURVE_TAG_CUBIC ) + { + point--; + tags--; + } continue; } @@ -2447,9 +2465,8 @@ Int y_min, Int y_max ) { - Int y_mid; - Int band_top = 0; - Int band_stack[32]; /* enough to bisect 32-bit int bands */ + Int band_stack[32]; /* enough to bisect 32-bit int bands */ + Int* band = band_stack; FT_TRACE6(( "%s pass [%d..%d]\n", @@ -2476,10 +2493,8 @@ FT_TRACE6(( "band [%d..%d]: to be bisected\n", y_min, y_max )); - y_mid = ( y_min + y_max ) >> 1; - - band_stack[band_top++] = y_min; - y_min = y_mid + 1; + *band++ = y_min; + y_min = ( y_min + y_max + 1 ) >> 1; } else { @@ -2490,11 +2505,11 @@ if ( ras.fProfile ) Draw_Sweep( RAS_VAR ); - if ( --band_top < 0 ) - break; + if ( band == band_stack ) + break; /* done */ y_max = y_min - 1; - y_min = band_stack[band_top]; + y_min = *--band; } } @@ -2517,11 +2532,7 @@ Render_Glyph( RAS_ARG ) { FT_Error error; - Long buffer[FT_MAX_BLACK_POOL]; - - ras.buff = buffer; - ras.sizeBuff = (&buffer)[1]; /* Points to right after buffer. */ Set_High_Precision( RAS_VARS ras.outline.flags & FT_OUTLINE_HIGH_PRECISION ); @@ -2665,6 +2676,9 @@ const FT_Outline* outline = (const FT_Outline*)params->source; const FT_Bitmap* target_map = params->target; + FT_ULong estimate; + int ret; + #ifndef FT_STATIC_RASTER black_TWorker worker[1]; #endif @@ -2712,7 +2726,36 @@ if ( ras.bPitch > 0 ) ras.bOrigin += ras.bTop * ras.bPitch; - return Render_Glyph( RAS_VAR ); + /* allocate memory based on empirical estimate from CJK fonts */ + estimate = ( ras.bTop + ras.bRight ) * 8UL + + 80UL * sizeof ( TProfile ) / sizeof ( Long ); + if ( estimate > FT_MAX_BLACK_POOL ) + { + FT_Error error; + FT_Memory memory = (FT_Memory)((black_PRaster)raster)->memory; + + + if ( FT_QNEW_ARRAY( ras.buff, estimate ) ) + ret = error; + else + { + ras.sizeBuff = ras.buff + estimate; + ret = Render_Glyph( RAS_VAR ); + FT_FREE( ras.buff ); + } + } + else + { + Long buffer[FT_MAX_BLACK_POOL]; /* stack allocation */ + + + ras.buff = buffer; + ras.sizeBuff = (&buffer)[1]; /* Points to right after buffer. */ + + ret = Render_Glyph( RAS_VAR ); + } + + return ret; } diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c index fc855cbb6b95..b894331935a8 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfobjs.c @@ -34,6 +34,10 @@ #include #endif +#ifdef TT_CONFIG_OPTION_VARC +#include +#endif + #include "sferrors.h" #ifdef TT_CONFIG_OPTION_BDF @@ -440,7 +444,10 @@ if ( tag == TTAG_ttcf ) { - FT_Int n; + FT_ULong version; + FT_ULong count; + FT_Bool has_extended_offsets; + FT_Int n; FT_TRACE3(( "sfnt_open_font: file is a collection\n" )); @@ -448,10 +455,13 @@ if ( FT_STREAM_READ_FIELDS( ttc_header_fields, &face->ttc_header ) ) return error; - FT_TRACE3(( " with %ld subfonts\n", - face->ttc_header.count )); + version = (FT_ULong)face->ttc_header.version; + count = (FT_ULong)face->ttc_header.count; - if ( face->ttc_header.count == 0 ) + has_extended_offsets = ( version >> 16 == 1 || version >> 16 == 2 ) && + ( version & 0xFFFF ) >= 1; + + if ( !has_extended_offsets && face->ttc_header.count == 0 ) return FT_THROW( Invalid_Table ); /* a rough size estimate: let's conservatively assume that there */ @@ -459,7 +469,38 @@ /* 28 bytes), thus we have (at least) `12 + 4*count' bytes for the */ /* size of the TTC header plus `28*count' bytes for all subfont */ /* headers */ - if ( (FT_ULong)face->ttc_header.count > stream->size / ( 28 + 4 ) ) + if ( count > stream->size / ( 28 + 4 ) ) + return FT_THROW( Array_Too_Large ); + + if ( has_extended_offsets ) + { + FT_TRACE3(( " with %lu compatibility subfonts\n", + count )); + + if ( FT_STREAM_SKIP( count * 4L ) ) + return error; + + /* In version 2.1 the extended count and offsets follow the */ + /* three version 2 DSIG fields. */ + if ( version >> 16 == 2 && FT_STREAM_SKIP( 12 ) ) + return error; + + if ( FT_READ_ULONG( count ) ) + return error; + + if ( count > FT_LONG_MAX ) + return FT_THROW( Array_Too_Large ); + + face->ttc_header.count = (FT_Long)count; + } + + FT_TRACE3(( " with %ld subfonts\n", + face->ttc_header.count )); + + if ( face->ttc_header.count == 0 ) + return FT_THROW( Invalid_Table ); + + if ( count > stream->size / ( 28 + 4 ) ) return FT_THROW( Array_Too_Large ); /* now read the offsets of each font in the file */ @@ -557,6 +598,24 @@ 0 ); #endif +#ifdef TT_CONFIG_OPTION_VARC + if ( !face->tt_varc ) + { + /* we want the VARC implementation from the `truetype' module only */ + FT_Module tt_module = FT_Get_Module( library, "truetype" ); + + + face->tt_varc = ft_module_get_service( tt_module, + FT_SERVICE_ID_VARC, + 0 ); + } + + if ( !face->face_varc ) + face->face_varc = ft_module_get_service( &face->root.driver->root, + FT_SERVICE_ID_VARC, + 0 ); +#endif + FT_TRACE2(( "SFNT driver\n" )); error = sfnt_open_font( stream, @@ -719,10 +778,12 @@ FT_FREE( default_values ); FT_FREE( instance_values ); - /* we don't support Multiple Master CFFs yet; */ - /* note that `glyf' or `CFF2' have precedence */ - if ( face->goto_table( face, TTAG_glyf, stream, 0 ) && + /* we don't support Multiple Master CFFs yet; */ + /* note that 'GLYF', 'glyf', or 'CFF2' have precedence */ + if ( face->goto_table( face, TTAG_GLYF, stream, 0 ) && + face->goto_table( face, TTAG_glyf, stream, 0 ) && face->goto_table( face, TTAG_CFF2, stream, 0 ) && + face->goto_table( face, TTAG_hvgl, stream, 0 ) && !face->goto_table( face, TTAG_CFF, stream, 0 ) ) num_instances = 0; @@ -862,12 +923,20 @@ /* do we have outlines in there? */ #ifdef FT_CONFIG_OPTION_INCREMENTAL + face->is_extended_glyf = + FT_BOOL( tt_face_lookup_table( face, TTAG_GLYF ) ); + has_outline = FT_BOOL( face->root.internal->incremental_interface || + face->is_extended_glyf || tt_face_lookup_table( face, TTAG_glyf ) || tt_face_lookup_table( face, TTAG_CFF ) || tt_face_lookup_table( face, TTAG_CFF2 ) ); #else - has_outline = FT_BOOL( tt_face_lookup_table( face, TTAG_glyf ) || + face->is_extended_glyf = + FT_BOOL( tt_face_lookup_table( face, TTAG_GLYF ) ); + + has_outline = FT_BOOL( face->is_extended_glyf || + tt_face_lookup_table( face, TTAG_glyf ) || tt_face_lookup_table( face, TTAG_CFF ) || tt_face_lookup_table( face, TTAG_CFF2 ) ); #endif @@ -950,6 +1019,7 @@ get_glyph_metrics ) { face->horizontal.number_Of_HMetrics = 0; + face->horz_metrics_count = 0; error = FT_Err_Ok; } #endif @@ -977,6 +1047,7 @@ get_glyph_metrics ) { face->horizontal.number_Of_HMetrics = 0; + face->horz_metrics_count = 0; error = FT_Err_Ok; } #endif @@ -1024,6 +1095,27 @@ LOAD_( colr ); } +#ifdef TT_CONFIG_OPTION_VARC + /* variable composite glyph support */ + if ( face->face_varc ) + { + FT_Service_VARC varc = (FT_Service_VARC)face->face_varc; + + + FT_TRACE2(( "'VARC' " )); + FT_TRACE3(( "-->\n" )); + + error = varc->load( (FT_Face)face, stream ); + + FT_TRACE2(( "%s\n", ( !error ) + ? "loaded" + : FT_ERR_EQ( error, Table_Missing ) + ? "missing" + : "failed to load" )); + FT_TRACE3(( "\n" )); + } +#endif + /* OpenType-SVG glyph support */ if ( sfnt->load_svg ) LOAD_( svg ); @@ -1037,7 +1129,7 @@ LOAD_( gpos ); #endif - face->root.num_glyphs = face->max_profile.numGlyphs; + face->root.num_glyphs = face->maxp_num_glyphs; /* Bit 8 of the `fsSelection' field in the `OS/2' table denotes */ /* a WWS-only font face. `WWS' stands for `weight', width', and */ @@ -1190,13 +1282,10 @@ tt_face_build_cmaps( face ); /* ignore errors */ - /* set the encoding fields */ { FT_Int m; -#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES - FT_Bool has_unicode = FALSE; -#endif + FT_UInt n; for ( m = 0; m < root->num_charmaps; m++ ) @@ -1206,38 +1295,58 @@ charmap->encoding = sfnt_find_encoding( charmap->platform_id, charmap->encoding_id ); + } + + for ( n = 0; n < face->num_dmap_charmaps; n++ ) + { + FT_CharMap charmap = &face->dmap_charmaps[n]->charmap; -#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES - if ( charmap->encoding == FT_ENCODING_UNICODE || - charmap->encoding == FT_ENCODING_MS_SYMBOL ) /* PUA */ - has_unicode = TRUE; + charmap->encoding = sfnt_find_encoding( charmap->platform_id, + charmap->encoding_id ); } - /* synthesize Unicode charmap if one is missing */ - if ( !has_unicode && - root->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) + tt_face_build_dmaps( face ); /* ignore errors */ + +#ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES { - FT_CharMapRec cmaprec; + FT_Bool has_unicode = FALSE; - cmaprec.face = root; - cmaprec.platform_id = TT_PLATFORM_MICROSOFT; - cmaprec.encoding_id = TT_MS_ID_UNICODE_CS; - cmaprec.encoding = FT_ENCODING_UNICODE; + for ( m = 0; m < root->num_charmaps; m++ ) + { + FT_CharMap charmap = root->charmaps[m]; - error = FT_CMap_New( (FT_CMap_Class)&tt_cmap_unicode_class_rec, - NULL, &cmaprec, NULL ); - if ( error && - FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) && - FT_ERR_NEQ( error, Unimplemented_Feature ) ) - goto Exit; - error = FT_Err_Ok; + if ( charmap->encoding == FT_ENCODING_UNICODE || + charmap->encoding == FT_ENCODING_MS_SYMBOL ) /* PUA */ + has_unicode = TRUE; + } + + /* synthesize Unicode charmap if one is missing */ + if ( !has_unicode && + root->face_flags & FT_FACE_FLAG_GLYPH_NAMES ) + { + FT_CharMapRec cmaprec; + + + cmaprec.face = root; + cmaprec.platform_id = TT_PLATFORM_MICROSOFT; + cmaprec.encoding_id = TT_MS_ID_UNICODE_CS; + cmaprec.encoding = FT_ENCODING_UNICODE; -#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ + error = FT_CMap_New( (FT_CMap_Class)&tt_cmap_unicode_class_rec, + NULL, &cmaprec, NULL ); + if ( error && + FT_ERR_NEQ( error, No_Unicode_Glyph_Name ) && + FT_ERR_NEQ( error, Unimplemented_Feature ) ) + goto Exit; + error = FT_Err_Ok; + } } + +#endif /* FT_CONFIG_OPTION_POSTSCRIPT_NAMES */ } #ifdef TT_CONFIG_OPTION_EMBEDDED_BITMAPS @@ -1470,6 +1579,17 @@ sfnt->free_colr( face ); } +#ifdef TT_CONFIG_OPTION_VARC + /* free VARC data */ + if ( face->face_varc ) + { + FT_Service_VARC varc = (FT_Service_VARC)face->face_varc; + + + varc->done( (FT_Face)face ); + } +#endif + #ifdef FT_CONFIG_OPTION_SVG /* free SVG data */ if ( sfnt->free_svg ) @@ -1502,9 +1622,14 @@ FT_Stream stream = FT_FACE_STREAM( face ); - /* simply release the 'cmap' table frame */ + tt_face_done_dmaps( face ); + + /* simply release the 'cmap' and 'DMAP' table frames */ FT_FRAME_RELEASE( face->cmap_table ); face->cmap_size = 0; + + FT_FRAME_RELEASE( face->dmap_table ); + face->dmap_size = 0; } face->horz_metrics_size = 0; @@ -1549,6 +1674,11 @@ FT_FREE( face->palette ); face->sfnt = NULL; + +#ifdef TT_CONFIG_OPTION_VARC + face->tt_varc = NULL; + face->face_varc = NULL; +#endif } diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c index b8a3030d9cb0..02125e3cba5d 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/sfwoff.c @@ -310,8 +310,12 @@ woff_offset += woff.privLength; } - if ( sfnt_offset != woff.totalSfntSize || - woff_offset != woff.length ) + /* Reject unrealistic size or compression factor */ + if ( sfnt_offset > 0x4000000UL || + ( sfnt_offset >> 6 ) > woff_offset || + sfnt_offset != woff.totalSfntSize || + woff_offset != woff.length ) + { FT_ERROR(( "woff_font_open: invalid `sfnt' table structure\n" )); error = FT_THROW( Invalid_Table ); diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c index f5837e65e86d..6fae7041b8ef 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.c @@ -17,6 +17,7 @@ #include +#include #include "sferrors.h" /* must come before `ftvalid.h' */ @@ -2936,7 +2937,8 @@ * Ranges are sorted by `uniStart'. */ -#ifdef TT_CONFIG_CMAP_FORMAT_14 +#if defined( TT_CONFIG_CMAP_FORMAT_14 ) || \ + defined( TT_CONFIG_CMAP_FORMAT_15 ) typedef struct TT_CMap14Rec_ { @@ -3009,9 +3011,23 @@ } - FT_CALLBACK_DEF( FT_Error ) - tt_cmap14_validate( FT_Byte* table, - FT_Validator valid ) + static FT_Bool + tt_cmap14_is_extended( FT_CMap cmap ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap_Class clazz = (TT_CMap_Class)( ttcmap->cmap_class + ? ttcmap->cmap_class + : cmap->clazz ); + + + return FT_BOOL( clazz->format == 15 ); + } + + + static FT_Error + tt_cmap14_validate_internal( FT_Byte* table, + FT_Validator valid, + FT_Bool is_extended ) { FT_Byte* p; FT_ULong length; @@ -3092,9 +3108,10 @@ /* and the non-default table (these glyphs are specified here) */ if ( nondefOff != 0 ) { - FT_Byte* ndp = table + nondefOff; + FT_Byte* ndp = table + nondefOff; FT_ULong numMappings; - FT_ULong i, lastUni = 0; + FT_UInt record_size = is_extended ? 6 : 5; + FT_ULong i, lastUni = 0; if ( ndp + 4 > valid->limit ) @@ -3102,14 +3119,15 @@ numMappings = TT_NEXT_ULONG( ndp ); - /* numMappings * 5 > (FT_ULong)( valid->limit - ndp ) ? */ - if ( numMappings > ( (FT_ULong)( valid->limit - ndp ) ) / 5 ) + if ( numMappings > + ( (FT_ULong)( valid->limit - ndp ) ) / record_size ) FT_INVALID_TOO_SHORT; for ( i = 0; i < numMappings; i++ ) { FT_ULong uni = TT_NEXT_UINT24( ndp ); - FT_ULong gid = TT_NEXT_USHORT( ndp ); + FT_ULong gid = is_extended ? TT_NEXT_UINT24( ndp ) + : TT_NEXT_USHORT( ndp ); if ( uni >= 0x110000UL ) /* end of Unicode */ @@ -3132,6 +3150,30 @@ } +#ifdef TT_CONFIG_CMAP_FORMAT_14 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap14_validate( FT_Byte* table, + FT_Validator valid ) + { + return tt_cmap14_validate_internal( table, valid, FALSE ); + } + +#endif /* TT_CONFIG_CMAP_FORMAT_14 */ + + +#ifdef TT_CONFIG_CMAP_FORMAT_15 + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap15_validate( FT_Byte* table, + FT_Validator valid ) + { + return tt_cmap14_validate_internal( table, valid, TRUE ); + } + +#endif /* TT_CONFIG_CMAP_FORMAT_15 */ + + FT_CALLBACK_DEF( FT_UInt ) tt_cmap14_char_index( FT_CMap cmap, FT_UInt32 char_code ) @@ -3160,9 +3202,13 @@ tt_cmap14_get_info( FT_CharMap cmap, TT_CMapInfo *cmap_info ) { - FT_UNUSED( cmap ); + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap_Class clazz = (TT_CMap_Class)( ttcmap->cmap_class + ? ttcmap->cmap_class + : FT_CMAP( cmap )->clazz ); + - cmap_info->format = 14; + cmap_info->format = clazz->format; /* subtable 14 does not define a language field */ cmap_info->language = 0xFFFFFFFFUL; @@ -3206,10 +3252,12 @@ static FT_UInt tt_cmap14_char_map_nondef_binary( FT_Byte *base, - FT_UInt32 char_code ) + FT_UInt32 char_code, + FT_Bool is_extended ) { FT_UInt32 numMappings = TT_PEEK_ULONG( base ); FT_UInt32 max, min; + FT_UInt record_size = is_extended ? 6 : 5; min = 0; @@ -3221,7 +3269,7 @@ while ( min < max ) { FT_UInt32 mid = ( min + max ) >> 1; - FT_Byte* p = base + 5 * mid; + FT_Byte* p = base + record_size * mid; FT_UInt32 uni = (FT_UInt32)TT_NEXT_UINT24( p ); @@ -3230,7 +3278,7 @@ else if ( char_code > uni ) min = mid + 1; else - return TT_PEEK_USHORT( p ); + return is_extended ? TT_PEEK_UINT24( p ) : TT_PEEK_USHORT( p ); } return 0; @@ -3278,6 +3326,7 @@ { TT_CMap ttcmap = (TT_CMap)cmap; TT_CMap ttucmap = (TT_CMap)ucmap; + FT_Bool is_extended = tt_cmap14_is_extended( cmap ); FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6, variantSelector ); @@ -3301,7 +3350,8 @@ if ( nondefOff != 0 ) return tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, - charcode ); + charcode, + is_extended ); return 0; } @@ -3313,6 +3363,7 @@ FT_UInt32 variantSelector ) { TT_CMap ttcmap = (TT_CMap)cmap; + FT_Bool is_extended = tt_cmap14_is_extended( cmap ); FT_Byte* p = tt_cmap14_find_variant( ttcmap->data + 6, variantSelector ); FT_ULong defOff; @@ -3331,7 +3382,8 @@ if ( nondefOff != 0 && tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, - charcode ) != 0 ) + charcode, + is_extended ) != 0 ) return 0; return -1; @@ -3375,6 +3427,7 @@ FT_UInt32 count = cmap14->num_selectors; FT_Byte* p = ttcmap->data + 10; FT_UInt32* q; + FT_Bool is_extended = tt_cmap14_is_extended( cmap ); if ( tt_cmap14_ensure( cmap14, ( count + 1 ), memory ) ) @@ -3392,7 +3445,8 @@ charCode ) ) || ( nondefOff != 0 && tt_cmap14_char_map_nondef_binary( ttcmap->data + nondefOff, - charCode ) != 0 ) ) + charCode, + is_extended ) != 0 ) ) { q[0] = varSel; q++; @@ -3462,7 +3516,8 @@ static FT_UInt32* tt_cmap14_get_nondef_chars( TT_CMap cmap, FT_Byte *p, - FT_Memory memory ) + FT_Memory memory, + FT_Bool is_extended ) { TT_CMap14 cmap14 = (TT_CMap14) cmap; FT_UInt32 numMappings; @@ -3479,7 +3534,7 @@ for ( i = 0; i < numMappings; i++ ) { ret[i] = (FT_UInt32)TT_NEXT_UINT24( p ); - p += 2; + p += is_extended ? 3 : 2; } ret[i] = 0; @@ -3495,6 +3550,7 @@ TT_CMap ttcmap = (TT_CMap)cmap; FT_Byte *p = tt_cmap14_find_variant( ttcmap->data + 6, variantSelector ); + FT_Bool is_extended = tt_cmap14_is_extended( cmap ); FT_Int i; FT_ULong defOff; FT_ULong nondefOff; @@ -3511,7 +3567,7 @@ if ( defOff == 0 ) return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff, - memory ); + memory, is_extended ); else if ( nondefOff == 0 ) return tt_cmap14_get_def_chars( ttcmap, ttcmap->data + defOff, memory ); @@ -3543,7 +3599,7 @@ memory ); if ( dcnt == 0 ) return tt_cmap14_get_nondef_chars( ttcmap, ttcmap->data + nondefOff, - memory ); + memory, is_extended ); if ( tt_cmap14_ensure( cmap14, ( dcnt + numMappings + 1 ), memory ) ) return NULL; @@ -3553,7 +3609,7 @@ dcnt = FT_NEXT_BYTE( dp ); di = 1; nuni = (FT_UInt32)TT_NEXT_UINT24( p ); - p += 2; + p += is_extended ? 3 : 2; ni = 1; i = 0; @@ -3583,7 +3639,7 @@ break; nuni = (FT_UInt32)TT_NEXT_UINT24( p ); - p += 2; + p += is_extended ? 3 : 2; } } @@ -3596,7 +3652,7 @@ while ( ni < numMappings ) { ret[i++] = (FT_UInt32)TT_NEXT_UINT24( p ); - p += 2; + p += is_extended ? 3 : 2; ni++; } } @@ -3626,6 +3682,8 @@ } +#ifdef TT_CONFIG_CMAP_FORMAT_14 + FT_DEFINE_TT_CMAP( tt_cmap14_class_rec, @@ -3651,6 +3709,35 @@ #endif /* TT_CONFIG_CMAP_FORMAT_14 */ +#ifdef TT_CONFIG_CMAP_FORMAT_15 + + FT_DEFINE_TT_CMAP( + tt_cmap15_class_rec, + + sizeof ( TT_CMap14Rec ), + + (FT_CMap_InitFunc) tt_cmap14_init, /* init */ + (FT_CMap_DoneFunc) tt_cmap14_done, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap14_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap14_char_next, /* char_next */ + + /* Format 15 extension functions */ + (FT_CMap_CharVarIndexFunc) tt_cmap14_char_var_index, + (FT_CMap_CharVarIsDefaultFunc)tt_cmap14_char_var_isdefault, + (FT_CMap_VariantListFunc) tt_cmap14_variants, + (FT_CMap_CharVariantListFunc) tt_cmap14_char_variants, + (FT_CMap_VariantCharListFunc) tt_cmap14_variant_chars, + + 15, + (TT_CMap_ValidateFunc)tt_cmap15_validate, /* validate */ + (TT_CMap_Info_GetFunc)tt_cmap14_get_info /* get_cmap_info */ + ) + +#endif /* TT_CONFIG_CMAP_FORMAT_15 */ + +#endif /* TT_CONFIG_CMAP_FORMAT_14 || TT_CONFIG_CMAP_FORMAT_15 */ + + /*************************************************************************/ /*************************************************************************/ /***** *****/ @@ -3773,22 +3860,506 @@ }; - /* parse the `cmap' table and build the corresponding TT_CMap objects */ - /* in the current face */ - /* */ - FT_LOCAL_DEF( FT_Error ) - tt_face_build_cmaps( TT_Face face ) + static void + tt_cmap_free( FT_CMap cmap ) + { + FT_Memory memory = FT_FACE_MEMORY( cmap->charmap.face ); + + + if ( cmap->clazz->done ) + cmap->clazz->done( cmap ); + + FT_FREE( cmap ); + } + + + static FT_Error + tt_cmap_new( FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_CMap *acmap ) + { + FT_Error error = FT_Err_Ok; + FT_Memory memory = FT_FACE_MEMORY( charmap->face ); + FT_CMap cmap = NULL; + + + if ( !FT_ALLOC( cmap, clazz->size ) ) + { + cmap->charmap = *charmap; + cmap->clazz = clazz; + + if ( clazz->init ) + { + error = clazz->init( cmap, init_data ); + if ( error ) + goto Fail; + } + } + + *acmap = cmap; + return error; + + Fail: + tt_cmap_free( cmap ); + *acmap = NULL; + return error; + } + + + static FT_Error + tt_face_add_dmap( TT_Face face, + FT_CMap_Class clazz, + FT_Pointer init_data, + FT_CharMap charmap, + FT_Int flags ) + { + FT_Error error; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_CMap cmap; + FT_UInt count = face->num_dmap_charmaps; + + + error = tt_cmap_new( clazz, init_data, charmap, &cmap ); + if ( error ) + return error; + + ((TT_CMap)cmap)->flags = flags; + + if ( FT_QRENEW_ARRAY( face->dmap_charmaps, count, count + 1 ) ) + { + tt_cmap_free( cmap ); + return error; + } + + face->dmap_charmaps[count] = cmap; + face->num_dmap_charmaps = count + 1; + + return FT_Err_Ok; + } + + + static FT_Bool + tt_cmap_is_variation( FT_CMap cmap ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + TT_CMap_Class clazz = (TT_CMap_Class)( ttcmap->cmap_class + ? ttcmap->cmap_class + : cmap->clazz ); + + + return FT_BOOL( clazz->format == 14 || clazz->format == 15 ); + } + + + static FT_CMap + tt_face_find_unicode_dmap( TT_Face face ) + { + FT_CMap* first = face->dmap_charmaps; + FT_CMap* cur; + + + if ( !first ) + return NULL; + + cur = first + face->num_dmap_charmaps; + for ( ; --cur >= first; ) + { + FT_CMap cmap = cur[0]; + + + if ( !cmap || + tt_cmap_is_variation( cmap ) || + cmap->charmap.encoding != FT_ENCODING_UNICODE ) + continue; + + if ( ( cmap->charmap.platform_id == TT_PLATFORM_MICROSOFT && + cmap->charmap.encoding_id == TT_MS_ID_UCS_4 ) || + ( cmap->charmap.platform_id == TT_PLATFORM_APPLE_UNICODE && + cmap->charmap.encoding_id == TT_APPLE_ID_UNICODE_32 ) || + ( cmap->charmap.platform_id == TT_PLATFORM_APPLE_UNICODE && + cmap->charmap.encoding_id == TT_APPLE_ID_FULL_UNICODE && + ( (TT_CMap_Class)cmap->clazz )->format == 13 ) ) + return cmap; + } + + cur = first + face->num_dmap_charmaps; + for ( ; --cur >= first; ) + { + FT_CMap cmap = cur[0]; + + + if ( cmap && + !tt_cmap_is_variation( cmap ) && + cmap->charmap.encoding == FT_ENCODING_UNICODE ) + return cmap; + } + + return NULL; + } + + + static FT_CMap + tt_face_find_dmap( TT_Face face, + FT_CharMap charmap ) + { + FT_CMap* first = face->dmap_charmaps; + FT_CMap* cur; + + + if ( !first ) + return NULL; + + if ( tt_cmap_is_variation( FT_CMAP( charmap ) ) ) + { + cur = first + face->num_dmap_charmaps; + for ( ; --cur >= first; ) + if ( cur[0] && tt_cmap_is_variation( cur[0] ) ) + return cur[0]; + + return NULL; + } + + if ( charmap->encoding == FT_ENCODING_UNICODE ) + return tt_face_find_unicode_dmap( face ); + + cur = first + face->num_dmap_charmaps; + for ( ; --cur >= first; ) + { + FT_CMap cmap = cur[0]; + + + if ( cmap && + !tt_cmap_is_variation( cmap ) && + cmap->charmap.platform_id == charmap->platform_id && + cmap->charmap.encoding_id == charmap->encoding_id ) + return cmap; + } + + cur = first + face->num_dmap_charmaps; + for ( ; --cur >= first; ) + { + FT_CMap cmap = cur[0]; + + + if ( cmap && + !tt_cmap_is_variation( cmap ) && + cmap->charmap.encoding == charmap->encoding ) + return cmap; + } + + return NULL; + } + + + FT_CALLBACK_DEF( void ) + tt_cmap_dmap_done( FT_CMap cmap ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_CMap_Class clazz = ttcmap->cmap_class; + + + cmap->clazz = clazz; + if ( clazz->done ) + clazz->done( cmap ); + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap_dmap_char_index( FT_CMap cmap, + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_UInt result; + + + result = ttcmap->dmap->clazz->char_index( ttcmap->dmap, char_code ); + if ( !result ) + result = ttcmap->cmap_class->char_index( cmap, char_code ); + + return result; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap_dmap_char_next( FT_CMap cmap, + FT_UInt32 *achar_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + + FT_UInt32 dmap_char = *achar_code; + FT_UInt32 cmap_char = *achar_code; + + FT_UInt dmap_glyph; + FT_UInt cmap_glyph; + + + dmap_glyph = ttcmap->dmap->clazz->char_next( ttcmap->dmap, &dmap_char ); + cmap_glyph = ttcmap->cmap_class->char_next( cmap, &cmap_char ); + + if ( dmap_glyph && ( !cmap_glyph || dmap_char <= cmap_char ) ) + { + *achar_code = dmap_char; + return dmap_glyph; + } + + *achar_code = cmap_char; + return cmap_glyph; + } + + + FT_CALLBACK_DEF( FT_UInt ) + tt_cmap_dmap_char_var_index( FT_CMap cmap, + FT_CMap unicode_cmap, + FT_UInt32 char_code, + FT_UInt32 variant_selector ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_CMap_Class clazz = ttcmap->dmap->clazz; + FT_Int is_default; + + + if ( clazz->char_var_default ) + { + is_default = clazz->char_var_default( ttcmap->dmap, + char_code, + variant_selector ); + if ( is_default == 1 ) + return unicode_cmap->clazz->char_index( unicode_cmap, char_code ); + if ( is_default == 0 ) + return clazz->char_var_index( ttcmap->dmap, unicode_cmap, + char_code, variant_selector ); + } + else if ( clazz->char_var_index ) + { + FT_UInt result = clazz->char_var_index( ttcmap->dmap, + unicode_cmap, + char_code, + variant_selector ); + + + if ( result ) + return result; + } + + clazz = ttcmap->cmap_class; + if ( clazz->char_var_index ) + return clazz->char_var_index( cmap, unicode_cmap, + char_code, variant_selector ); + + return 0; + } + + + FT_CALLBACK_DEF( FT_Int ) + tt_cmap_dmap_char_var_isdefault( FT_CMap cmap, + FT_UInt32 char_code, + FT_UInt32 variant_selector ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + FT_CMap_Class clazz = ttcmap->dmap->clazz; + FT_Int result = -1; + + + if ( clazz->char_var_default ) + result = clazz->char_var_default( ttcmap->dmap, + char_code, variant_selector ); + + clazz = ttcmap->cmap_class; + if ( result == -1 && clazz->char_var_default ) + result = clazz->char_var_default( cmap, char_code, + variant_selector ); + + return result; + } + + + static FT_UInt32* + tt_cmap_dmap_merge( TT_CMap cmap, + FT_UInt32 *dmap_list, + FT_UInt32 *cmap_list ) + { + TT_Face face = (TT_Face)cmap->cmap.charmap.face; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error = FT_Err_Ok; + + FT_UInt32 dmap_count = 0; + FT_UInt32 cmap_count = 0; + FT_UInt32 old_max = face->dmap_max_results; + + FT_UInt32 i = 0; + FT_UInt32 j = 0; + FT_UInt32 k = 0; + + + if ( dmap_list ) + while ( dmap_list[dmap_count] ) + dmap_count++; + if ( cmap_list ) + while ( cmap_list[cmap_count] ) + cmap_count++; + + if ( !dmap_count && !cmap_count ) + return NULL; + + if ( dmap_count >= 0xFFFFFFFFUL - cmap_count ) + return NULL; + + if ( dmap_count + cmap_count + 1 > face->dmap_max_results ) + { + if ( FT_QRENEW_ARRAY( face->dmap_results, old_max, + dmap_count + cmap_count + 1 ) ) + return NULL; + + face->dmap_max_results = dmap_count + cmap_count + 1; + } + + while ( i < dmap_count && j < cmap_count ) + { + if ( dmap_list[i] < cmap_list[j] ) + face->dmap_results[k++] = dmap_list[i++]; + else if ( cmap_list[j] < dmap_list[i] ) + face->dmap_results[k++] = cmap_list[j++]; + else + { + face->dmap_results[k++] = dmap_list[i++]; + j++; + } + } + + while ( i < dmap_count ) + face->dmap_results[k++] = dmap_list[i++]; + while ( j < cmap_count ) + face->dmap_results[k++] = cmap_list[j++]; + + face->dmap_results[k] = 0; + return face->dmap_results; + } + + + FT_CALLBACK_DEF( FT_UInt32* ) + tt_cmap_dmap_variants( FT_CMap cmap, + FT_Memory memory ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + + FT_CMap_Class dclazz = ttcmap->dmap->clazz; + FT_CMap_Class cclazz = ttcmap->cmap_class; + + FT_UInt32* dmap_list = NULL; + FT_UInt32* cmap_list = NULL; + + + if ( dclazz->variant_list ) + dmap_list = dclazz->variant_list( ttcmap->dmap, memory ); + if ( cclazz->variant_list ) + cmap_list = cclazz->variant_list( cmap, memory ); + + return tt_cmap_dmap_merge( ttcmap, dmap_list, cmap_list ); + } + + + FT_CALLBACK_DEF( FT_UInt32* ) + tt_cmap_dmap_char_variants( FT_CMap cmap, + FT_Memory memory, + FT_UInt32 char_code ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + + FT_CMap_Class dclazz = ttcmap->dmap->clazz; + FT_CMap_Class cclazz = ttcmap->cmap_class; + + FT_UInt32* dmap_list = NULL; + FT_UInt32* cmap_list = NULL; + + + if ( dclazz->charvariant_list ) + dmap_list = dclazz->charvariant_list( ttcmap->dmap, memory, + char_code ); + if ( cclazz->charvariant_list ) + cmap_list = cclazz->charvariant_list( cmap, memory, char_code ); + + return tt_cmap_dmap_merge( ttcmap, dmap_list, cmap_list ); + } + + + FT_CALLBACK_DEF( FT_UInt32* ) + tt_cmap_dmap_variant_chars( FT_CMap cmap, + FT_Memory memory, + FT_UInt32 variant_selector ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + + FT_CMap_Class dclazz = ttcmap->dmap->clazz; + FT_CMap_Class cclazz = ttcmap->cmap_class; + + FT_UInt32* dmap_list = NULL; + FT_UInt32* cmap_list = NULL; + + + if ( dclazz->variantchar_list ) + dmap_list = dclazz->variantchar_list( ttcmap->dmap, memory, + variant_selector ); + if ( cclazz->variantchar_list ) + cmap_list = cclazz->variantchar_list( cmap, memory, + variant_selector ); + + return tt_cmap_dmap_merge( ttcmap, dmap_list, cmap_list ); + } + + + FT_CALLBACK_DEF( FT_Error ) + tt_cmap_dmap_get_info( FT_CharMap charmap, + TT_CMapInfo *cmap_info ) + { + TT_CMap cmap = (TT_CMap)charmap; + TT_CMap_Class clazz = (TT_CMap_Class)cmap->cmap_class; + + + if ( clazz->get_cmap_info ) + return clazz->get_cmap_info( charmap, cmap_info ); + + return FT_THROW( Invalid_CharMap_Format ); + } + + + FT_DEFINE_TT_CMAP( + tt_cmap_dmap_class_rec, + + sizeof ( TT_CMapRec ), + + (FT_CMap_InitFunc) NULL, /* init */ + (FT_CMap_DoneFunc) tt_cmap_dmap_done, /* done */ + (FT_CMap_CharIndexFunc)tt_cmap_dmap_char_index, /* char_index */ + (FT_CMap_CharNextFunc) tt_cmap_dmap_char_next, /* char_next */ + + (FT_CMap_CharVarIndexFunc) tt_cmap_dmap_char_var_index, + (FT_CMap_CharVarIsDefaultFunc)tt_cmap_dmap_char_var_isdefault, + (FT_CMap_VariantListFunc) tt_cmap_dmap_variants, + (FT_CMap_CharVariantListFunc) tt_cmap_dmap_char_variants, + (FT_CMap_VariantCharListFunc) tt_cmap_dmap_variant_chars, + + 0, + (TT_CMap_ValidateFunc)NULL, + (TT_CMap_Info_GetFunc)tt_cmap_dmap_get_info + ) + + + /* parse a `cmap'-shaped table and build the corresponding TT_CMap */ + /* objects in the current face */ + /* */ + static FT_Error + tt_face_build_cmaps_from_table( TT_Face face, + FT_Byte* table, + FT_ULong table_size, + FT_Bool is_dmap ) { - FT_Byte* const table = face->cmap_table; FT_Byte* limit; FT_UInt volatile num_cmaps; - FT_Byte* volatile p = table; - FT_Library library = FT_FACE_LIBRARY( face ); - - FT_UNUSED( library ); + FT_Byte* volatile p = table; - if ( !p || face->cmap_size < 4 ) + if ( !p || table_size < 4 ) return FT_THROW( Invalid_Table ); /* Version 1.8.3 of the OpenType specification contains the following */ @@ -3805,7 +4376,7 @@ num_cmaps = TT_NEXT_USHORT( p ); FT_TRACE4(( "tt_face_build_cmaps: %u cmaps\n", num_cmaps )); - limit = table + face->cmap_size; + limit = table + table_size; for ( ; num_cmaps > 0 && p + 8 <= limit; num_cmaps-- ) { FT_CharMapRec charmap; @@ -3818,7 +4389,7 @@ charmap.encoding = FT_ENCODING_NONE; /* will be filled later */ offset = TT_NEXT_ULONG( p ); - if ( offset && offset <= face->cmap_size - 2 ) + if ( offset && offset <= table_size - 2 ) { FT_Byte* volatile cmap = table + offset; volatile FT_UInt format = TT_PEEK_USHORT( cmap ); @@ -3838,7 +4409,7 @@ ft_validator_init( FT_VALIDATOR( &valid ), cmap, limit, FT_VALIDATE_DEFAULT ); - valid.num_glyphs = (FT_UInt)face->max_profile.numGlyphs; + valid.num_glyphs = face->maxp_num_glyphs; if ( ft_setjmp( FT_VALIDATOR( &valid )->jump_buffer) == 0 ) { @@ -3848,20 +4419,31 @@ if ( !valid.validator.error ) { - FT_CMap ttcmap; + FT_CMap ttcmap; + FT_Error new_error; /* It might make sense to store the single variation */ /* selector cmap somewhere special. But it would have to be */ /* in the public FT_FaceRec, and we can't change that. */ - if ( !FT_CMap_New( (FT_CMap_Class)clazz, - cmap, &charmap, &ttcmap ) ) + if ( is_dmap ) + new_error = tt_face_add_dmap( face, (FT_CMap_Class)clazz, + cmap, &charmap, + (FT_Int)error ); + else + new_error = FT_CMap_New( (FT_CMap_Class)clazz, + cmap, &charmap, &ttcmap ); + + if ( !new_error && !is_dmap ) { /* it is simpler to directly set `flags' than adding */ /* a parameter to FT_CMap_New */ ((TT_CMap)ttcmap)->flags = (FT_Int)error; } + + if ( new_error && FT_ERR_EQ( new_error, Out_Of_Memory ) ) + return new_error; } else { @@ -3884,6 +4466,162 @@ } + /* parse the 'cmap' and 'DMAP' tables */ + FT_LOCAL_DEF( FT_Error ) + tt_face_build_cmaps( TT_Face face ) + { + FT_Error error; + + + error = tt_face_build_cmaps_from_table( face, + face->cmap_table, + face->cmap_size, + FALSE ); + if ( error || !face->dmap_table ) + return error; + + return tt_face_build_cmaps_from_table( face, + face->dmap_table, + face->dmap_size, + TRUE ); + } + + + static FT_Error + tt_face_expose_dmap( TT_Face face, + FT_CMap dmap ) + { + FT_Face root = FT_FACE( face ); + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error = FT_Err_Ok; + + FT_Int count = root->num_charmaps; + FT_UInt i; + + + if ( FT_QRENEW_ARRAY( root->charmaps, count, count + 1 ) ) + return error; + + root->charmaps[count] = &dmap->charmap; + root->num_charmaps = count + 1; + + for ( i = 0; i < face->num_dmap_charmaps; i++ ) + if ( face->dmap_charmaps[i] == dmap ) + { + face->dmap_charmaps[i] = NULL; + break; + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( FT_Error ) + tt_face_build_dmaps( TT_Face face ) + { + FT_Face root = FT_FACE( face ); + FT_Error error; + + FT_Int num_cmaps = root->num_charmaps; + FT_Int i; + FT_UInt j; + + + if ( !face->num_dmap_charmaps ) + return FT_Err_Ok; + + /* Apply the best matching DMAP subtable to every selectable cmap. */ + for ( i = 0; i < num_cmaps; i++ ) + { + FT_CMap cmap = FT_CMAP( root->charmaps[i] ); + FT_CMap dmap = tt_face_find_dmap( face, &cmap->charmap ); + + + if ( dmap ) + { + TT_CMap ttcmap = (TT_CMap)cmap; + + + ttcmap->cmap_class = cmap->clazz; + ttcmap->dmap = dmap; + cmap->clazz = (FT_CMap_Class)&tt_cmap_dmap_class_rec; + } + } + + /* If DMAP supplies an encoding absent from cmap, expose it directly. */ + for ( j = 0; j < face->num_dmap_charmaps; j++ ) + { + FT_CMap dmap = face->dmap_charmaps[j]; + FT_Bool found = FALSE; + + + if ( !dmap || tt_cmap_is_variation( dmap ) ) + continue; + + for ( i = 0; i < root->num_charmaps; i++ ) + { + FT_CMap cmap = FT_CMAP( root->charmaps[i] ); + + + if ( !tt_cmap_is_variation( cmap ) && + cmap->charmap.encoding == dmap->charmap.encoding ) + { + found = TRUE; + break; + } + } + + if ( !found ) + { + FT_CMap best = dmap; + + + if ( dmap->charmap.encoding == FT_ENCODING_UNICODE ) + best = tt_face_find_unicode_dmap( face ); + + error = tt_face_expose_dmap( face, best ); + if ( error ) + return error; + } + } + + /* A variation subtable is not selectable as an ordinary charmap. */ + for ( i = 0; i < root->num_charmaps; i++ ) + if ( tt_cmap_is_variation( FT_CMAP( root->charmaps[i] ) ) ) + return FT_Err_Ok; + + for ( j = 0; j < face->num_dmap_charmaps; j++ ) + { + FT_CMap dmap = face->dmap_charmaps[j]; + + + if ( dmap && tt_cmap_is_variation( dmap ) ) + return tt_face_expose_dmap( face, dmap ); + } + + return FT_Err_Ok; + } + + + FT_LOCAL_DEF( void ) + tt_face_done_dmaps( TT_Face face ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_UInt i; + + + for ( i = 0; i < face->num_dmap_charmaps; i++ ) + if ( face->dmap_charmaps[i] ) + tt_cmap_free( face->dmap_charmaps[i] ); + + FT_FREE( face->dmap_charmaps ); + face->num_dmap_charmaps = 0; + + FT_FREE( face->dmap_results ); + face->dmap_max_results = 0; + } + + FT_LOCAL_DEF( FT_Error ) tt_get_cmap_info( FT_CharMap charmap, TT_CMapInfo *cmap_info ) diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h index fdb34f525e3c..4b8cbb3197a1 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmap.h @@ -32,9 +32,11 @@ FT_BEGIN_HEADER typedef struct TT_CMapRec_ { - FT_CMapRec cmap; - FT_Byte* data; /* pointer to in-memory cmap table */ - FT_Int flags; /* for format 4 only */ + FT_CMapRec cmap; + FT_Byte* data; /* pointer to in-memory cmap table */ + FT_Int flags; /* for format 4 only */ + FT_CMap_Class cmap_class; /* class before applying 'DMAP' */ + FT_CMap dmap; /* overriding 'DMAP' subtable */ } TT_CMapRec, *TT_CMap; @@ -112,6 +114,12 @@ FT_BEGIN_HEADER FT_LOCAL( FT_Error ) tt_face_build_cmaps( TT_Face face ); + FT_LOCAL( FT_Error ) + tt_face_build_dmaps( TT_Face face ); + + FT_LOCAL( void ) + tt_face_done_dmaps( TT_Face face ); + /* used in tt-cmaps service */ FT_LOCAL( FT_Error ) tt_get_cmap_info( FT_CharMap charmap, diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h index c17ac5bba15d..a704690dae6f 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcmapc.h @@ -52,5 +52,9 @@ TTCMAPCITEM( tt_cmap14_class_rec ) #endif +#ifdef TT_CONFIG_CMAP_FORMAT_15 + TTCMAPCITEM( tt_cmap15_class_rec ) +#endif + /* END */ diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c index b22e279b3465..2272ec3739a2 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttcolr.c @@ -85,6 +85,7 @@ FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW = 29, FT_COLR_PAINTFORMAT_INTERNAL_SKEW_CENTER = 30, FT_COLR_PAINTFORMAT_INTERNAL_VAR_SKEW_CENTER = 31, + FT_COLR_PAINTFORMAT_INTERNAL_GLYPH2 = 33, } FT_PaintFormat_Internal; @@ -645,7 +646,9 @@ apaint->format = (FT_PaintFormat)FT_NEXT_BYTE( p ); - if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX ) + if ( apaint->format >= FT_COLR_PAINT_FORMAT_MAX && + (FT_PaintFormat_Internal)apaint->format != + FT_COLR_PAINTFORMAT_INTERNAL_GLYPH2 ) return 0; if ( apaint->format == FT_COLR_PAINTFORMAT_COLR_LAYERS ) @@ -879,12 +882,21 @@ return 1; } - if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH ) + if ( apaint->format == FT_COLR_PAINTFORMAT_GLYPH || + (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_GLYPH2 ) { - ENSURE_READ_BYTES( 2 ); + FT_Bool is_glyph2 = (FT_PaintFormat_Internal)apaint->format == + FT_COLR_PAINTFORMAT_INTERNAL_GLYPH2; + + + ENSURE_READ_BYTES( ( is_glyph2 ? 3 : 2 ) ); apaint->u.glyph.paint.p = child_table_p; apaint->u.glyph.paint.insert_root_transform = 0; - apaint->u.glyph.glyphID = FT_NEXT_USHORT( p ); + apaint->u.glyph.glyphID = is_glyph2 ? FT_NEXT_UOFF3( p ) + : FT_NEXT_USHORT( p ); + + apaint->format = FT_COLR_PAINTFORMAT_GLYPH; return 1; } @@ -1862,39 +1874,78 @@ alpha = face->palette[color_index].alpha; } - /* XXX Convert if srcSlot.bitmap is not grey? */ src = srcSlot->bitmap.buffer; dst = dstSlot->bitmap.buffer + dstSlot->bitmap.pitch * ( dstSlot->bitmap_top - srcSlot->bitmap_top ) + 4 * ( srcSlot->bitmap_left - dstSlot->bitmap_left ); - for ( y = 0; y < srcSlot->bitmap.rows; y++ ) + switch ( srcSlot->bitmap.pixel_mode ) { - for ( x = 0; x < srcSlot->bitmap.width; x++ ) - { - int aa = src[x]; - int fa = alpha * aa / 255; + case FT_PIXEL_MODE_GRAY: + for ( y = 0; y < srcSlot->bitmap.rows; y++ ) + { + for ( x = 0; x < srcSlot->bitmap.width; x++ ) + { + int aa = src[x]; + int fa = alpha * aa / 255; - int fb = b * fa / 255; - int fg = g * fa / 255; - int fr = r * fa / 255; + int fb = b * fa / 255; + int fg = g * fa / 255; + int fr = r * fa / 255; - int ba2 = 255 - fa; + int ba2 = 255 - fa; - int bb = dst[4 * x + 0]; - int bg = dst[4 * x + 1]; - int br = dst[4 * x + 2]; - int ba = dst[4 * x + 3]; + int bb = dst[4 * x + 0]; + int bg = dst[4 * x + 1]; + int br = dst[4 * x + 2]; + int ba = dst[4 * x + 3]; + dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb ); + dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg ); + dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr ); + dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa ); + } - dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb ); - dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg ); - dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr ); - dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + fa ); - } + src += srcSlot->bitmap.pitch; + dst += dstSlot->bitmap.pitch; + } + break; + + case FT_PIXEL_MODE_MONO: + { + int fb = b * alpha / 255; + int fg = g * alpha / 255; + int fr = r * alpha / 255; + + int ba2 = 255 - alpha; + + for ( y = 0; y < srcSlot->bitmap.rows; y++ ) + { + for ( x = 0; x < srcSlot->bitmap.width; x++ ) + { + if ( src[x >> 3] & ( 0x80 >> ( x & 7 ) ) ) + { + int bb = dst[4 * x + 0]; + int bg = dst[4 * x + 1]; + int br = dst[4 * x + 2]; + int ba = dst[4 * x + 3]; + + dst[4 * x + 0] = (FT_Byte)( bb * ba2 / 255 + fb ); + dst[4 * x + 1] = (FT_Byte)( bg * ba2 / 255 + fg ); + dst[4 * x + 2] = (FT_Byte)( br * ba2 / 255 + fr ); + dst[4 * x + 3] = (FT_Byte)( ba * ba2 / 255 + alpha ); + } + } + + src += srcSlot->bitmap.pitch; + dst += dstSlot->bitmap.pitch; + } + } + break; - src += srcSlot->bitmap.pitch; - dst += dstSlot->bitmap.pitch; + default: + /* Reject pixel modes other than GRAY/MONO. */ + return FT_Err_Invalid_Glyph_Format; } return FT_Err_Ok; diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c index e17d07a971ce..74d319e01f17 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttload.c @@ -227,7 +227,9 @@ /* ignore in general). */ if ( table.Tag == TTAG_hmtx || - table.Tag == TTAG_vmtx ) + table.Tag == TTAG_HMTX || + table.Tag == TTAG_vmtx || + table.Tag == TTAG_VMTX ) valid_entries++; else { @@ -439,7 +441,9 @@ else if ( entry.Length > stream->size - entry.Offset ) { if ( entry.Tag == TTAG_hmtx || - entry.Tag == TTAG_vmtx ) + entry.Tag == TTAG_HMTX || + entry.Tag == TTAG_vmtx || + entry.Tag == TTAG_VMTX ) { #ifdef FT_DEBUG_LEVEL_TRACE FT_ULong old_length = entry.Length; @@ -749,7 +753,8 @@ FT_Stream stream ) { FT_Error error; - TT_MaxProfile* maxProfile = &face->max_profile; + TT_MaxProfile* maxProfile = &face->max_profile; + FT_Bool is_extended = FALSE; static const FT_Frame_Field maxp_fields[] = { @@ -782,12 +787,37 @@ }; - error = face->goto_table( face, TTAG_maxp, stream, 0 ); + face->maxp_num_glyphs = 0; + + error = face->goto_table( face, TTAG_MAXP, stream, 0 ); + if ( !error ) + is_extended = TRUE; + else if ( FT_ERR_EQ( error, Table_Missing ) ) + error = face->goto_table( face, TTAG_maxp, stream, 0 ); + if ( error ) goto Exit; - if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) - goto Exit; + if ( is_extended ) + { + FT_UInt32 num_glyphs; + + + if ( FT_READ_LONG( maxProfile->version ) || + FT_READ_UOFF3( num_glyphs ) ) + goto Exit; + + face->maxp_num_glyphs = num_glyphs; + maxProfile->numGlyphs = num_glyphs > 0xFFFFU ? 0xFFFFU + : (FT_UShort)num_glyphs; + } + else + { + if ( FT_STREAM_READ_FIELDS( maxp_fields, maxProfile ) ) + goto Exit; + + face->maxp_num_glyphs = maxProfile->numGlyphs; + } maxProfile->maxPoints = 0; maxProfile->maxContours = 0; @@ -829,7 +859,7 @@ } } - FT_TRACE3(( "numGlyphs: %hu\n", maxProfile->numGlyphs )); + FT_TRACE3(( "numGlyphs: %u\n", face->maxp_num_glyphs )); Exit: return error; @@ -1135,6 +1165,21 @@ if ( FT_FRAME_EXTRACT( face->cmap_size, face->cmap_table ) ) face->cmap_size = 0; + if ( error ) + goto Exit; + + error = face->goto_table( face, TTAG_DMAP, stream, &face->dmap_size ); + if ( error ) + { + face->dmap_size = 0; + if ( FT_ERR_EQ( error, Table_Missing ) ) + error = FT_Err_Ok; + goto Exit; + } + + if ( FT_FRAME_EXTRACT( face->dmap_size, face->dmap_table ) ) + face->dmap_size = 0; + Exit: return error; } diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c index 60dce87d841a..e52df3f583e0 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttmtx.c @@ -81,13 +81,15 @@ if ( vertical ) { - tag = TTAG_vmtx; + tag = face->vert_metrics_is_extended ? TTAG_VMTX + : TTAG_vmtx; ptable_offset = &face->vert_metrics_offset; ptable_size = &face->vert_metrics_size; } else { - tag = TTAG_hmtx; + tag = face->horz_metrics_is_extended ? TTAG_HMTX + : TTAG_hmtx; ptable_offset = &face->horz_metrics_offset; ptable_size = &face->horz_metrics_size; } @@ -132,13 +134,17 @@ { FT_Error error; TT_HoriHeader* header; + FT_UInt32* metrics_count; + FT_Bool* is_extended; + FT_ULong lower_tag; + FT_ULong upper_tag; static const FT_Frame_Field metrics_header_fields[] = { #undef FT_STRUCTURE #define FT_STRUCTURE TT_HoriHeader - FT_FRAME_START( 36 ), + FT_FRAME_START( 34 ), FT_FRAME_ULONG ( Version ), FT_FRAME_SHORT ( Ascender ), FT_FRAME_SHORT ( Descender ), @@ -155,7 +161,6 @@ FT_FRAME_SHORT ( Reserved[2] ), FT_FRAME_SHORT ( Reserved[3] ), FT_FRAME_SHORT ( metric_Data_Format ), - FT_FRAME_USHORT( number_Of_HMetrics ), FT_FRAME_END }; @@ -165,27 +170,71 @@ void *v = &face->vertical; - error = face->goto_table( face, TTAG_vhea, stream, 0 ); + header = (TT_HoriHeader*)v; + metrics_count = &face->vert_metrics_count; + is_extended = &face->vert_metrics_is_extended; + lower_tag = TTAG_vhea; + upper_tag = TTAG_VHEA; + } + else + { + header = &face->horizontal; + metrics_count = &face->horz_metrics_count; + is_extended = &face->horz_metrics_is_extended; + lower_tag = TTAG_hhea; + upper_tag = TTAG_HHEA; + } + + *metrics_count = 0; + *is_extended = FALSE; + + if ( face->is_extended_glyf ) + { + error = face->goto_table( face, upper_tag, stream, 0 ); if ( error ) goto Fail; - header = (TT_HoriHeader*)v; + *is_extended = TRUE; } else { - error = face->goto_table( face, TTAG_hhea, stream, 0 ); + error = face->goto_table( face, lower_tag, stream, 0 ); + if ( FT_ERR_EQ( error, Table_Missing ) ) + { + error = face->goto_table( face, upper_tag, stream, 0 ); + if ( !error ) + *is_extended = TRUE; + } if ( error ) goto Fail; - - header = &face->horizontal; } if ( FT_STREAM_READ_FIELDS( metrics_header_fields, header ) ) goto Fail; + if ( *is_extended ) + { + if ( FT_READ_ULONG( *metrics_count ) ) + goto Fail; + } + else + { + FT_UShort count; + + + if ( FT_READ_USHORT( count ) ) + goto Fail; + + *metrics_count = count; + } + + header->number_Of_HMetrics = *metrics_count > 0xFFFFU + ? 0xFFFFU + : (FT_UShort)*metrics_count; + FT_TRACE3(( "Ascender: %5d\n", header->Ascender )); FT_TRACE3(( "Descender: %5d\n", header->Descender )); - FT_TRACE3(( "number_Of_Metrics: %5u\n", header->number_Of_HMetrics )); + FT_TRACE3(( "number_Of_Metrics: %5lu\n", (FT_ULong)*metrics_count )); header->long_metrics = NULL; header->short_metrics = NULL; @@ -231,11 +280,10 @@ FT_Short *abearing, FT_UShort *aadvance ) { - FT_Error error; - FT_Stream stream = face->root.stream; - TT_HoriHeader* header; - FT_ULong table_pos, table_size, table_end; - FT_UShort k; + FT_Error error; + FT_Stream stream = face->root.stream; + FT_ULong table_pos, table_size, table_end; + FT_UInt32 k; #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT FT_Service_MetricsVariations var = @@ -245,24 +293,19 @@ if ( vertical ) { - void* v = &face->vertical; - - - header = (TT_HoriHeader*)v; table_pos = face->vert_metrics_offset; table_size = face->vert_metrics_size; + k = face->vert_metrics_count; } else { - header = &face->horizontal; table_pos = face->horz_metrics_offset; table_size = face->horz_metrics_size; + k = face->horz_metrics_count; } table_end = table_pos + table_size; - k = header->number_Of_HMetrics; - if ( k > 0 ) { if ( gindex < (FT_UInt)k ) @@ -306,7 +349,9 @@ } #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT - if ( var && FT_IS_VARIATION( &face->root ) ) + if ( var && + ( FT_IS_VARIATION( &face->root ) || + FT_IS_NAMED_INSTANCE( &face->root ) ) ) { FT_Face f = FT_FACE( face ); FT_Int a = (FT_Int)*aadvance; diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c index 98603e115eab..0e0bd0fd366d 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttpost.c @@ -337,10 +337,10 @@ /* UNDOCUMENTED! The number of glyphs in this table can be smaller */ /* than the value in the maxp table (cf. cyberbit.ttf). */ - if ( post_len < 34 || - FT_STREAM_SKIP( 32 ) || - FT_READ_USHORT( num_glyphs ) || - num_glyphs > face->max_profile.numGlyphs || + if ( post_len < 34 || + FT_STREAM_SKIP( 32 ) || + FT_READ_USHORT( num_glyphs ) || + num_glyphs > face->maxp_num_glyphs || num_glyphs == 0 ) goto Exit; @@ -422,7 +422,7 @@ if ( !face ) return FT_THROW( Invalid_Face_Handle ); - if ( idx >= (FT_UInt)face->max_profile.numGlyphs ) + if ( idx >= face->maxp_num_glyphs ) return FT_THROW( Invalid_Glyph_Index ); #ifdef FT_CONFIG_OPTION_POSTSCRIPT_NAMES @@ -463,7 +463,7 @@ /* version 1.0 is only valid with 258 glyphs */ else if ( format == 0x00010000L && - face->max_profile.numGlyphs == 258 ) + face->maxp_num_glyphs == 258 ) *PSname = MAC_NAME( idx ); /* nothing to do for format == 0x00030000L */ diff --git a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c index 1655e40b6814..d479b6a0b78e 100644 --- a/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c +++ b/src/java.desktop/share/native/libfreetype/src/sfnt/ttsbit.c @@ -1602,9 +1602,10 @@ metrics->horiBearingY = (FT_Short)( originOffsetY + metrics->height ); metrics->vertBearingY = (FT_Short)originOffsetY; - metrics->horiAdvance = (FT_UShort)( aadvance * - face->root.size->metrics.x_ppem / - face->header.Units_Per_EM ); + metrics->horiAdvance = + (FT_UShort)FT_MulDiv( aadvance, + face->root.size->metrics.x_ppem, + face->header.Units_Per_EM ); if ( face->vertical_info ) tt_face_get_metrics( face, TRUE, glyph_index, &abearing, &aadvance ); @@ -1615,9 +1616,10 @@ aadvance = (FT_UShort)FT_ABS( face->horizontal.Ascender - face->horizontal.Descender ); - metrics->vertAdvance = (FT_UShort)( aadvance * - face->root.size->metrics.x_ppem / - face->header.Units_Per_EM ); + metrics->vertAdvance = + (FT_UShort)FT_MulDiv( aadvance, + face->root.size->metrics.x_ppem, + face->header.Units_Per_EM ); } return error; diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c index 0f7b63937d70..69805f08a270 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftgrays.c @@ -68,11 +68,14 @@ * * This renderer has the following advantages: * - * - It doesn't need an intermediate bitmap. Instead, one can supply a - * callback function that will be called by the renderer to draw gray - * spans on any target surface. You can thus do direct composition on - * any kind of bitmap, provided that you give the renderer the right - * callback. + * - It doesn't need an intermediate bitmap. Instead, linked lists + * of cells (pixels visited by an outline) are stored, which requires + * less memory and can be maintained on the stack for small glyphs. + * + * - One can supply a callback function that will be called by the + * renderer to draw gray spans on any target surface. You can thus + * do direct composition on any kind of bitmap, provided that you give + * the renderer the right callback. * * - A perfect anti-aliaser, i.e., it computes the _exact_ coverage on * each pixel cell by straight segments. @@ -464,7 +467,10 @@ typedef ptrdiff_t FT_PtrDist; } TPixmap; - /* maximum number of gray cells in the buffer */ + /* Maximum number of gray cells in the stack buffer; */ + /* for example, a buffer of 680 cells can accommodate */ + /* a glyph with the taxicab perimeter of 680 pixels. */ + /* A larger buffer can be allocated when necessary. */ #if FT_RENDER_POOL_SIZE > 2048 #define FT_MAX_GRAY_POOL ( FT_RENDER_POOL_SIZE / sizeof ( TCell ) ) #else @@ -485,16 +491,14 @@ typedef ptrdiff_t FT_PtrDist; typedef struct gray_TWorker_ { - FT_BBox cbox; - - TCoord min_ex, max_ex; /* min and max integer pixel coordinates */ - TCoord min_ey, max_ey; - TCoord count_ey; /* same as (max_ey - min_ey) */ + TCoord min_ex, min_ey; /* min and max integer pixel coordinates */ + TCoord max_ex, max_ey; int error; /* pool overflow exception */ + PCell buffer; /* buffer */ + PCell cell_null; /* last cell, used as dumpster and limit */ PCell cell; /* current cell */ PCell cell_free; /* call allocation next free slot */ - PCell cell_null; /* last cell, used as dumpster and limit */ PCell* ycells; /* array of cell linked-lists; one per */ /* vertical coordinate in the current band */ @@ -581,14 +585,11 @@ typedef ptrdiff_t FT_PtrDist; /* Note that if a cell is to the left of the clipping region, it is */ /* actually set to the (min_ex-1) horizontal position. */ - TCoord ey_index = ey - ras.min_ey; - - - if ( ey_index < 0 || ey_index >= ras.count_ey || ex >= ras.max_ex ) + if ( ey < ras.min_ey || ey >= ras.max_ey || ex >= ras.max_ex ) ras.cell = ras.cell_null; else { - PCell* pcell = ras.ycells + ey_index; + PCell* pcell = ras.ycells + ( ey - ras.min_ey ); PCell cell; @@ -1502,15 +1503,14 @@ typedef ptrdiff_t FT_PtrDist; tags = outline->tags + first; tag = FT_CURVE_TAG( tags[0] ); - /* A contour cannot start with a cubic control point! */ - if ( tag == FT_CURVE_TAG_CUBIC ) - goto Invalid_Outline; - /* check first point to determine origin */ - if ( tag == FT_CURVE_TAG_CONIC ) + if ( tag != FT_CURVE_TAG_ON ) { - /* first point is conic control. Yes, this happens. */ - if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) + char last_tag = FT_CURVE_TAG( outline->tags[last] ); + + + /* first point is a control point. Yes, this happens. */ + if ( last_tag == FT_CURVE_TAG_ON ) { /* start at last point if it is on the curve */ v_start = v_last; @@ -1518,9 +1518,12 @@ typedef ptrdiff_t FT_PtrDist; } else { - /* if both first and last points are conic, */ - /* start at their middle and record its position */ - /* for closure */ + if ( last_tag != tag ) + goto Invalid_Outline; + + /* if both first and last points are controls, */ + /* start at their middle and record its position */ + /* for closure */ v_start.x = ( v_start.x + v_last.x ) / 2; v_start.y = ( v_start.y + v_last.y ) / 2; @@ -1636,11 +1639,24 @@ typedef ptrdiff_t FT_PtrDist; if ( point <= limit ) { FT_Vector vec; + FT_Vector v_middle; + + tag = FT_CURVE_TAG( tags[0] ); vec.x = SCALED( point->x ); vec.y = SCALED( point->y ); + if ( tag == FT_CURVE_TAG_CUBIC ) + { + v_middle.x = ( vec2.x + vec.x ) / 2; + v_middle.y = ( vec2.y + vec.y ) / 2; + + vec = v_middle; + } + else if ( tag != FT_CURVE_TAG_ON ) + goto Invalid_Outline; + FT_TRACE5(( " cubic to (%.2f, %.2f)" " with controls (%.2f, %.2f) and (%.2f, %.2f)\n", vec.x / 64.0, vec.y / 64.0, @@ -1649,6 +1665,12 @@ typedef ptrdiff_t FT_PtrDist; error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); if ( error ) goto Exit; + + if ( tag == FT_CURVE_TAG_CUBIC ) + { + point--; + tags--; + } continue; } @@ -1804,7 +1826,7 @@ typedef ptrdiff_t FT_PtrDist; FT_FILL_RULE( coverage, cover, fill ); span[n].coverage = (unsigned char)coverage; - span[n].x = (unsigned short)x; + span[n].x = (short)x; span[n].len = (unsigned short)( cell->x - x ); if ( ++n == FT_MAX_GRAY_SPANS ) @@ -1823,7 +1845,7 @@ typedef ptrdiff_t FT_PtrDist; FT_FILL_RULE( coverage, area, fill ); span[n].coverage = (unsigned char)coverage; - span[n].x = (unsigned short)cell->x; + span[n].x = (short)cell->x; span[n].len = 1; if ( ++n == FT_MAX_GRAY_SPANS ) @@ -1861,101 +1883,75 @@ typedef ptrdiff_t FT_PtrDist; static int gray_convert_glyph( RAS_ARG ) { - TCell buffer[FT_MAX_GRAY_POOL]; - size_t height = (size_t)( ras.cbox.yMax - ras.cbox.yMin ); - size_t n = FT_MAX_GRAY_POOL / 8; - TCoord y; TCoord bands[32]; /* enough to accommodate bisections */ - TCoord* band; + TCoord* band = bands; int continued = 0; int error = Smooth_Err_Ok; /* Initialize the null cell at the end of the poll. */ - ras.cell_null = buffer + FT_MAX_GRAY_POOL - 1; ras.cell_null->x = CELL_MAX_X_VALUE; ras.cell_null->area = 0; ras.cell_null->cover = 0; ras.cell_null->next = NULL; /* set up vertical bands */ - ras.ycells = (PCell*)buffer; - - if ( height > n ) - { - /* two divisions rounded up */ - n = ( height + n - 1 ) / n; - height = ( height + n - 1 ) / n; - } + ras.ycells = (PCell*)ras.buffer; - for ( y = ras.cbox.yMin; y < ras.cbox.yMax; ) + while ( 1 ) { - ras.min_ey = y; - y += height; - ras.max_ey = FT_MIN( y, ras.cbox.yMax ); - - ras.count_ey = ras.max_ey - ras.min_ey; + size_t n; + TCoord i, count = ras.max_ey - ras.min_ey; - band = bands; - band[1] = ras.cbox.xMin; - band[0] = ras.cbox.xMax; - - do - { - TCoord i; + /* memory management: zero out and skip ycells */ + for ( i = 0; i < count; ++i ) + ras.ycells[i] = ras.cell_null; - ras.min_ex = band[1]; - ras.max_ex = band[0]; + n = ( (size_t)count * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) + / sizeof ( TCell ); - /* memory management: zero out and skip ycells */ - for ( i = 0; i < ras.count_ey; ++i ) - ras.ycells[i] = ras.cell_null; + ras.cell_free = ras.buffer + n; + ras.cell = ras.cell_null; + ras.error = Smooth_Err_Ok; - n = ( (size_t)ras.count_ey * sizeof ( PCell ) + sizeof ( TCell ) - 1 ) - / sizeof ( TCell ); + error = gray_convert_glyph_inner( RAS_VAR_ continued ); + continued = 1; - ras.cell_free = buffer + n; - ras.cell = ras.cell_null; - ras.error = Smooth_Err_Ok; + if ( !error ) + { + if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */ + gray_sweep_direct( RAS_VAR ); + else + gray_sweep( RAS_VAR ); - error = gray_convert_glyph_inner( RAS_VAR_ continued ); - continued = 1; + if ( band == bands ) + break; /* done */ - if ( !error ) - { - if ( ras.render_span ) /* for FT_RASTER_FLAG_DIRECT only */ - gray_sweep_direct( RAS_VAR ); - else - gray_sweep( RAS_VAR ); - band--; - continue; - } - else if ( error != Smooth_Err_Raster_Overflow ) - goto Exit; + ras.max_ey = ras.min_ey; + ras.min_ey = *--band; + continue; + } + else if ( error != Smooth_Err_Raster_Overflow ) + goto Exit; - /* render pool overflow; we will reduce the render band by half */ - i = ( band[0] - band[1] ) >> 1; + /* render pool overflow, reduce the render band by half */ + count >>= 1; - /* this should never happen even with tiny rendering pool */ - if ( i == 0 ) - { - FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); - error = FT_THROW( Raster_Overflow ); - goto Exit; - } + /* this happens only if the rendering pool is too small */ + if ( count == 0 ) + { + FT_TRACE7(( "gray_convert_glyph: rotten glyph\n" )); + error = FT_THROW( Raster_Overflow ); + goto Exit; + } - band++; - band[1] = band[0]; - band[0] += i; - } while ( band >= bands ); + *band++ = ras.min_ey; + ras.min_ey += count; } Exit: - ras.cell = ras.cell_free = ras.cell_null = NULL; - ras.ycells = NULL; - return error; } @@ -1964,6 +1960,9 @@ typedef ptrdiff_t FT_PtrDist; gray_raster_render( FT_Raster raster, const FT_Raster_Params* params ) { + FT_ULong estimate; + int ret; + const FT_Outline* outline = (const FT_Outline*)params->source; const FT_Bitmap* target_map = params->target; @@ -2003,7 +2002,10 @@ typedef ptrdiff_t FT_PtrDist; ras.render_span = (FT_Raster_Span_Func)params->gray_spans; ras.render_span_data = params->user; - ras.cbox = params->clip_box; + ras.min_ex = (TCoord)params->clip_box.xMin; + ras.min_ey = (TCoord)params->clip_box.yMin; + ras.max_ex = (TCoord)params->clip_box.xMax; + ras.max_ey = (TCoord)params->clip_box.yMax; } else { @@ -2029,17 +2031,45 @@ typedef ptrdiff_t FT_PtrDist; ras.render_span = (FT_Raster_Span_Func)NULL; ras.render_span_data = NULL; - ras.cbox.xMin = 0; - ras.cbox.yMin = 0; - ras.cbox.xMax = (FT_Pos)target_map->width; - ras.cbox.yMax = (FT_Pos)target_map->rows; + ras.min_ex = 0; + ras.min_ey = 0; + ras.max_ex = (TCoord)target_map->width; + ras.max_ey = (TCoord)target_map->rows; } /* exit if nothing to do */ - if ( ras.cbox.xMin >= ras.cbox.xMax || ras.cbox.yMin >= ras.cbox.yMax ) + if ( ras.min_ex >= ras.max_ex || ras.min_ey >= ras.max_ey ) return Smooth_Err_Ok; - return gray_convert_glyph( RAS_VAR ); + /* allocate memory based on empirical estimate from CJK fonts */ + estimate = ( ras.max_ex - ras.min_ex + ras.max_ey - ras.min_ey ) * 10UL; + if ( estimate > FT_MAX_GRAY_POOL ) + { + FT_Error error; + FT_Memory memory = (FT_Memory)((gray_PRaster)raster)->memory; + + + if ( FT_QNEW_ARRAY( ras.buffer, estimate ) ) + ret = error; + else + { + ras.cell_null = ras.buffer + estimate - 1; + ret = gray_convert_glyph( RAS_VAR ); + FT_FREE( ras.buffer ); + } + } + else + { + TCell buffer[FT_MAX_GRAY_POOL]; /* stack allocation */ + + + ras.buffer = buffer; + ras.cell_null = ras.buffer + FT_MAX_GRAY_POOL - 1; + + ret = gray_convert_glyph( RAS_VAR ); + } + + return ret; } diff --git a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c index 7378e6adc46d..f5a3de65d801 100644 --- a/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c +++ b/src/java.desktop/share/native/libfreetype/src/smooth/ftsmooth.c @@ -124,7 +124,8 @@ for ( ; count--; spans++ ) - for ( dst = dst_line + spans->x * 3, w = spans->len; w--; dst += 3 ) + for ( dst = dst_line + (unsigned short)spans->x * 3, + w = spans->len; w--; dst += 3 ) *dst = spans->coverage; } @@ -151,7 +152,7 @@ params.clip_box.xMin = 0; params.clip_box.yMin = 0; - params.clip_box.xMax = bitmap->width; + params.clip_box.xMax = bitmap->width / 3; params.clip_box.yMax = bitmap->rows; if ( bitmap->pitch < 0 ) @@ -290,7 +291,8 @@ for ( ; count--; spans++ ) - for ( dst = dst_line + spans->x, w = spans->len; w--; dst++ ) + for ( dst = dst_line + (unsigned short)spans->x, + w = spans->len; w--; dst++ ) { dst[0] += ( spans->coverage * target->wght[0] + 85 ) >> 8; dst[1] += ( spans->coverage * target->wght[1] + 85 ) >> 8; @@ -385,7 +387,8 @@ for ( ; count--; spans++ ) - for ( dst = dst_line + spans->x, w = spans->len; w--; dst++ ) + for ( dst = dst_line + (unsigned short)spans->x, + w = spans->len; w--; dst++ ) { dst[ 0] += ( spans->coverage * target->wght[0] + 85 ) >> 8; dst[ pitch] += ( spans->coverage * target->wght[1] + 85 ) >> 8; @@ -473,7 +476,7 @@ unsigned char* dst = target->origin - ( y / SCALE ) * target->pitch; - unsigned short x; + unsigned int x, i; unsigned int cover, sum; @@ -487,8 +490,9 @@ cover = ( spans->coverage + SCALE * SCALE / 2 ) / ( SCALE * SCALE ); for ( x = 0; x < spans->len; x++ ) { - sum = dst[( spans->x + x ) / SCALE] + cover; - dst[( spans->x + x ) / SCALE] = (unsigned char)( sum - ( sum >> 8 ) ); + i = ( (unsigned short)spans->x + x ) / SCALE; + sum = dst[i] + cover; + dst[i] = (unsigned char)( sum - ( sum >> 8 ) ); } } } diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c index 90d6e8105787..b9530b518bcd 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttdriver.c @@ -32,6 +32,10 @@ #include #include +#ifdef TT_CONFIG_OPTION_VARC +#include +#endif + #include "ttdriver.h" #include "ttgload.h" #include "ttpload.h" @@ -40,6 +44,10 @@ #include "ttgxvar.h" #endif +#ifdef TT_CONFIG_OPTION_VARC +#include "ttvarc.h" +#endif + #include "tterrors.h" @@ -456,15 +464,6 @@ FT_Error error; - if ( !slot ) - return FT_THROW( Invalid_Slot_Handle ); - - if ( !size ) - return FT_THROW( Invalid_Size_Handle ); - - if ( !face ) - return FT_THROW( Invalid_Face_Handle ); - #ifdef FT_CONFIG_OPTION_INCREMENTAL if ( glyph_index >= (FT_UInt)face->num_glyphs && !face->internal->incremental_interface ) @@ -493,6 +492,39 @@ load_flags |= FT_LOAD_NO_HINTING; } +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* + * DirectWrite treats ClearType symmetric grid fitting independently + * from symmetric smoothing. Resolve the grid-fitting decision from the + * same policy source that GETINFO uses for symmetric smoothing. + * + * Only native v40 horizontal-LCD hinting participates. Caller-disabled + * native hinting and the other interpreter/rendering modes are left + * alone. + */ + if ( FT_LOAD_TARGET_MODE( load_flags ) == FT_RENDER_MODE_LCD && + !( load_flags & FT_LOAD_NO_HINTING ) && + !FT_IS_TRICKY( face ) ) + { + TT_Driver driver = (TT_Driver)FT_FACE_DRIVER( face ); + + + if ( driver->interpreter_version == TT_INTERPRETER_VERSION_40 ) + { + FT_Bool grid_fit; + + + tt_face_get_cleartype_policy( (TT_Face)face, + size->metrics.y_ppem, + NULL, + &grid_fit ); + + if ( !grid_fit ) + load_flags |= FT_LOAD_NO_HINTING; + } + } +#endif + /* use hinted metrics only if we load a glyph with hinting */ ttsize->metrics = ( load_flags & FT_LOAD_NO_HINTING ) ? &size->metrics @@ -571,6 +603,21 @@ #endif /* TT_CONFIG_OPTION_GX_VAR_SUPPORT */ +#ifdef TT_CONFIG_OPTION_VARC + + FT_DEFINE_SERVICE_VARCREC( + tt_service_varc, + + tt_face_init_varc_axes, + tt_face_load_varc, + tt_face_free_varc, + tt_face_has_varc_glyph, + tt_face_load_varc_glyph + ) + +#endif /* TT_CONFIG_OPTION_VARC */ + + static const FT_Service_TrueTypeEngineRec tt_service_truetype_engine = { #ifdef TT_USE_BYTECODE_INTERPRETER @@ -592,7 +639,19 @@ ) -#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT +#if defined( TT_CONFIG_OPTION_GX_VAR_SUPPORT ) && \ + defined( TT_CONFIG_OPTION_VARC ) + FT_DEFINE_SERVICEDESCREC7( + tt_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TRUETYPE, + FT_SERVICE_ID_MULTI_MASTERS, &tt_service_gx_multi_masters, + FT_SERVICE_ID_METRICS_VARIATIONS, &tt_service_metrics_variations, + FT_SERVICE_ID_VARC, &tt_service_varc, + FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, + FT_SERVICE_ID_TT_GLYF, &tt_service_truetype_glyf, + FT_SERVICE_ID_PROPERTIES, &tt_service_properties ) +#elif defined( TT_CONFIG_OPTION_GX_VAR_SUPPORT ) FT_DEFINE_SERVICEDESCREC6( tt_services, @@ -602,6 +661,15 @@ FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, FT_SERVICE_ID_TT_GLYF, &tt_service_truetype_glyf, FT_SERVICE_ID_PROPERTIES, &tt_service_properties ) +#elif defined( TT_CONFIG_OPTION_VARC ) + FT_DEFINE_SERVICEDESCREC5( + tt_services, + + FT_SERVICE_ID_FONT_FORMAT, FT_FONT_FORMAT_TRUETYPE, + FT_SERVICE_ID_VARC, &tt_service_varc, + FT_SERVICE_ID_TRUETYPE_ENGINE, &tt_service_truetype_engine, + FT_SERVICE_ID_TT_GLYF, &tt_service_truetype_glyf, + FT_SERVICE_ID_PROPERTIES, &tt_service_properties ) #else FT_DEFINE_SERVICEDESCREC4( tt_services, diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c index dcff7c3bb713..f665361646dd 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgload.c @@ -34,6 +34,10 @@ #include "ttgxvar.h" #endif +#ifdef TT_CONFIG_OPTION_VARC +#include "ttvarc.h" +#endif + #include "tterrors.h" @@ -51,7 +55,7 @@ * * Simple glyph flags. */ -#define ON_CURVE_POINT 0x01 /* same value as FT_CURVE_TAG_ON */ +#define ON_CURVE_POINT 0x01 #define X_SHORT_VECTOR 0x02 #define Y_SHORT_VECTOR 0x04 #define REPEAT_FLAG 0x08 @@ -60,6 +64,7 @@ #define Y_POSITIVE 0x20 /* two meanings depending on Y_SHORT_VECTOR */ #define SAME_Y 0x20 #define OVERLAP_SIMPLE 0x40 /* retained as FT_OUTLINE_OVERLAP */ +#define CUBIC_FLAG 0x80 /************************************************************************** @@ -79,6 +84,7 @@ #define OVERLAP_COMPOUND 0x0400 /* retained as FT_OUTLINE_OVERLAP */ #define SCALED_COMPONENT_OFFSET 0x0800 #define UNSCALED_COMPONENT_OFFSET 0x1000 +#define GID_IS_24_BIT 0x2000 #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT @@ -345,8 +351,8 @@ FT_Byte* limit = load->limit; FT_GlyphLoader gloader = load->gloader; FT_Outline* outline = &gloader->current.outline; - FT_Int n_contours = load->n_contours; - FT_Int n_points; + FT_UInt n_contours = (FT_UInt)load->n_contours; + FT_UInt n_points; FT_UShort n_ins; FT_Byte *flag, *flag_limit; @@ -354,7 +360,6 @@ FT_Vector *vec, *vec_limit; FT_Pos x, y; FT_UShort *cont, *cont_limit; - FT_Int last; /* check that we can add the contours to the glyph */ @@ -363,27 +368,25 @@ goto Fail; /* check space for contours array + instructions count */ - if ( n_contours >= 0xFFF || p + 2 * n_contours + 2 > limit ) + if ( n_contours >= 0xFFFU || p + 2 * n_contours + 2 > limit ) goto Invalid_Outline; /* reading the contours' endpoints & number of points */ cont = outline->contours; cont_limit = cont + n_contours; - last = -1; + n_points = 0; for ( ; cont < cont_limit; cont++ ) { *cont = FT_NEXT_USHORT( p ); - if ( *cont <= last ) + if ( *cont < n_points ) goto Invalid_Outline; - last = *cont; + n_points = *cont + 1U; } - n_points = last + 1; - - FT_TRACE5(( " # of points: %d\n", n_points )); + FT_TRACE5(( " # of points: %u\n", n_points )); /* note that we will add four phantom points later */ error = FT_GLYPHLOADER_CHECK_POINTS( gloader, n_points + 4, 0 ); @@ -527,8 +530,9 @@ y += delta; vec->y = y; - /* the cast is for stupid compilers */ - *flag = (FT_Byte)( f & ON_CURVE_POINT ); + *flag = (FT_Byte)( f & ON_CURVE_POINT ); + if ( load->face->is_extended_glyf && ( f & CUBIC_FLAG ) ) + *flag |= FT_CURVE_TAG_CUBIC; } outline->n_points = (FT_UShort)n_points; @@ -570,7 +574,7 @@ if ( error ) goto Fail; - /* check space */ + /* check space for the flags and a 16-bit glyph ID */ if ( p + 4 > limit ) goto Invalid_Composite; @@ -579,7 +583,16 @@ subglyph->arg1 = subglyph->arg2 = 0; subglyph->flags = FT_NEXT_USHORT( p ); - subglyph->index = FT_NEXT_USHORT( p ); + if ( loader->face->is_extended_glyf && + ( subglyph->flags & GID_IS_24_BIT ) != 0 ) + { + if ( p + 3 > limit ) + goto Invalid_Composite; + + subglyph->index = (FT_Int)FT_NEXT_UOFF3( p ); + } + else + subglyph->index = FT_NEXT_USHORT( p ); /* we reject composites that have components */ /* with invalid glyph indices */ @@ -1148,7 +1161,15 @@ IS_HINTED( loader->load_flags ) ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - if ( !loader->exec->backward_compatibility ) + TT_Driver driver = + (TT_Driver)FT_FACE_DRIVER( (FT_Face)loader->face ); + + + /* v40 approximates native ClearType's fine horizontal grid by */ + /* leaving X offsets of components unrounded. */ + if ( driver->interpreter_version != TT_INTERPRETER_VERSION_40 || + loader->exec->mode == FT_RENDER_MODE_MONO || + FT_IS_TRICKY( (FT_Face)loader->face ) ) #endif x = FT_PIX_ROUND( x ); @@ -2539,6 +2560,84 @@ #endif /* FT_CONFIG_OPTION_SVG */ +#ifdef TT_CONFIG_OPTION_VARC + + /* check for VARC glyphs */ + if ( face->varc && + tt_face_has_varc_glyph( (FT_Face)face, glyph_index ) ) + { + FT_TRACE3(( "Loading VARC glyph\n" )); + + error = tt_face_load_varc_glyph( (FT_Face)face, + (FT_GlyphSlot)glyph, + glyph_index, + load_flags ); + if ( !error ) + { + FT_Short left_bearing = 0; + FT_Short top_bearing = 0; + FT_UShort advance_width = 0; + FT_UShort advance_height = 0; + + + /* Get advance width and height. */ + TT_Get_HMetrics( face, glyph_index, + &left_bearing, + &advance_width ); + TT_Get_VMetrics( face, glyph_index, + 0, + &top_bearing, + &advance_height ); + + glyph->linearHoriAdvance = advance_width; + glyph->linearVertAdvance = advance_height; + +#ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT + { + FT_Int advance = (FT_Int)advance_width; + + + tt_hadvance_adjust( (FT_Face)face, glyph_index, &advance ); + advance_width = (FT_UShort)advance; + } +#endif + + { + FT_BBox bbox; + + + FT_Outline_Get_CBox( &glyph->outline, &bbox ); + + glyph->metrics.horiBearingX = bbox.xMin; + glyph->metrics.horiBearingY = bbox.yMax; + glyph->metrics.width = SUB_LONG( bbox.xMax, bbox.xMin ); + glyph->metrics.height = SUB_LONG( bbox.yMax, bbox.yMin ); + } + + if ( load_flags & FT_LOAD_NO_SCALE ) + { + /* Under NO_SCALE the advance is in font units (no 26.6 shift), */ + /* like the normal glyf path (pp2.x - pp1.x). */ + glyph->metrics.horiAdvance = advance_width; + glyph->metrics.vertAdvance = advance_height; + } + else + { + glyph->metrics.horiAdvance = FT_MulFix( advance_width, + size->metrics->x_scale ); + glyph->metrics.vertAdvance = FT_MulFix( advance_height, + size->metrics->y_scale ); + } + + FT_TRACE3(( "Successfully loaded VARC glyph\n" )); + goto Exit; + } + + FT_TRACE3(( "Failed to load VARC glyph, falling back to glyf\n" )); + } + +#endif /* TT_CONFIG_OPTION_VARC */ + error = tt_loader_init( &loader, size, glyph, load_flags, FALSE ); if ( error ) goto Exit; diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c index d392e9bc1c23..4ae7d4805dc7 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.c @@ -129,6 +129,12 @@ * stream :: * The data stream. * + * scratch :: + * A caller-provided scratch buffer for temporary storage. + * + * scratch_cap :: + * The size of `scratch`. + * * @Output: * point_cnt :: * The number of points read. A zero value means that @@ -140,8 +146,10 @@ * special value ALL_POINTS. */ static FT_UShort* - ft_var_readpackedpoints( FT_Stream stream, - FT_UInt *point_cnt ) + ft_var_readpackedpoints( FT_Stream stream, + FT_UInt *point_cnt, + FT_UShort* scratch, + FT_UInt scratch_cap ) { FT_UShort *points = NULL; FT_UInt n; @@ -166,7 +174,11 @@ n |= FT_GET_BYTE(); } - if ( FT_QNEW_ARRAY( points, n ) ) + /* Re-use `scratch` if it is large enough; this avoids */ + /* a heap allocation per tuple in the common case. */ + if ( scratch && n <= scratch_cap ) + points = scratch; + else if ( FT_QNEW_ARRAY( points, n ) ) return NULL; p = stream->cursor; @@ -218,7 +230,8 @@ Fail: FT_TRACE1(( "ft_var_readpackedpoints: invalid table\n" )); - FT_FREE( points ); + if ( points != scratch ) + FT_FREE( points ); return NULL; } @@ -244,6 +257,12 @@ * delta_cnt :: * The number of deltas to be read. * + * scratch :: + * A caller-provided scratch buffer for temporary storage. + * + * scratch_cap :: + * The size of `scratch`. + * * @Return: * An array of FT_Fixed containing the deltas for the affected * points. (This only gets the deltas for one dimension. It will @@ -256,7 +275,9 @@ */ static FT_Fixed* ft_var_readpackeddeltas( FT_Stream stream, - FT_UInt delta_cnt ) + FT_UInt delta_cnt, + FT_Fixed* scratch, + FT_UInt scratch_cap ) { FT_Fixed *deltas = NULL; FT_UInt runcnt, cnt; @@ -266,7 +287,11 @@ FT_Error error; - if ( FT_QNEW_ARRAY( deltas, delta_cnt ) ) + /* Re-use `scratch` if it is large enough; this avoids */ + /* a heap allocation per tuple in the common case. */ + if ( scratch && delta_cnt <= scratch_cap ) + deltas = scratch; + else if ( FT_QNEW_ARRAY( deltas, delta_cnt ) ) return NULL; p = stream->cursor; @@ -314,7 +339,8 @@ Fail: FT_TRACE1(( "ft_var_readpackeddeltas: invalid table\n" )); - FT_FREE( deltas ); + if ( deltas != scratch ) + FT_FREE( deltas ); return NULL; } @@ -1175,11 +1201,12 @@ GX_ItemVarData varData; - FT_UInt master; - FT_Int64 returnValue = FT_INT64_ZERO; - FT_UInt shift_base = 1; - FT_UInt per_region_size; - FT_Byte* bytes; + FT_UInt master; + FT_Int64 returnValue = FT_INT64_ZERO; + FT_UInt shift_base = 1; + FT_UInt per_region_size; + FT_Byte* bytes; + FT_Fixed* regionScalars; if ( !ttface->blend || !ttface->blend->normalizedcoords ) @@ -1217,6 +1244,67 @@ bytes = varData->deltaSet + per_region_size * innerIndex; + /* The region scalars depend only on the normalized coordinates, which */ + /* are constant while glyphs are loaded; yet this function is called */ + /* once per item (e.g., per glyph for 'HVAR' advances). Cache the */ + /* scalars per store and recompute only when the coordinates change. */ + /* `regionScalars` stays NULL (falling back to recomputation) if the */ + /* cache cannot be allocated. */ + regionScalars = itemStore->regionScalars; + { + FT_Fixed* ncoords = ttface->blend->normalizedcoords; + FT_Bool fresh = FT_BOOL( regionScalars != NULL ); + FT_UInt a; + + + if ( fresh ) + { + for ( a = 0; a < itemStore->axisCount; a++ ) + if ( itemStore->cachedCoords[a] != ncoords[a] ) + { + fresh = FALSE; + break; + } + } + + if ( !fresh ) + { + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error = FT_Err_Ok; + + FT_UNUSED( error ); + + + if ( !regionScalars ) + { + if ( !FT_QNEW_ARRAY( itemStore->regionScalars, + itemStore->regionCount ) && + !FT_QNEW_ARRAY( itemStore->cachedCoords, + itemStore->axisCount ) ) + regionScalars = itemStore->regionScalars; + else + { + FT_FREE( itemStore->regionScalars ); + FT_FREE( itemStore->cachedCoords ); + } + } + + if ( regionScalars ) + { + FT_UInt r; + + + for ( r = 0; r < itemStore->regionCount; r++ ) + regionScalars[r] = tt_calculate_scalar( + itemStore->varRegionList[r].axisList, + itemStore->axisCount, + ncoords ); + for ( a = 0; a < itemStore->axisCount; a++ ) + itemStore->cachedCoords[a] = ncoords[a]; + } + } + } + /* outer loop steps through master designs to be blended */ for ( master = 0; master < varData->regionIdxCount; master++ ) { @@ -1224,10 +1312,12 @@ GX_AxisCoords axis = itemStore->varRegionList[regionIndex].axisList; - FT_Fixed scalar = tt_calculate_scalar( - axis, - itemStore->axisCount, - ttface->blend->normalizedcoords ); + FT_Fixed scalar = regionScalars + ? regionScalars[regionIndex] + : tt_calculate_scalar( + axis, + itemStore->axisCount, + ttface->blend->normalizedcoords ); if ( scalar ) @@ -1755,7 +1845,7 @@ FT_UShort axisCount; FT_UShort globalCoordCount; FT_ULong offsetToCoord; - FT_UShort glyphCount; + FT_UInt32 glyphCount; FT_UShort flags; FT_ULong offsetToData; @@ -1781,16 +1871,24 @@ static FT_Error ft_var_load_gvar( TT_Face face ) { - FT_Stream stream = FT_FACE_STREAM( face ); - FT_Memory memory = stream->memory; - GX_Blend blend = face->blend; - FT_Error error; - FT_UInt i, j; - FT_Byte* bytes; - FT_ULong table_len; - FT_ULong gvar_start; - FT_ULong offsetToData; - FT_ULong offsets_len; + FT_Error error; + + FT_Stream stream = FT_FACE_STREAM( face ); + FT_Memory memory = stream->memory; + + GX_Blend blend = face->blend; + FT_Bool blend_created = FALSE; + FT_Bool is_extended = FALSE; + + FT_UInt i, j; + FT_Byte* bytes; + FT_ULong table_len; + FT_ULong gvar_start; + FT_ULong header_size; + + FT_ULong offsetToData; + FT_ULong offsets_len; + GX_GVar_Head gvar_head; static const FT_Frame_Field gvar_fields[] = @@ -1799,33 +1897,68 @@ #undef FT_STRUCTURE #define FT_STRUCTURE GX_GVar_Head - FT_FRAME_START( 20 ), + FT_FRAME_START( 12 ), FT_FRAME_LONG ( version ), FT_FRAME_USHORT( axisCount ), FT_FRAME_USHORT( globalCoordCount ), FT_FRAME_ULONG ( offsetToCoord ), - FT_FRAME_USHORT( glyphCount ), - FT_FRAME_USHORT( flags ), - FT_FRAME_ULONG ( offsetToData ), FT_FRAME_END }; FT_TRACE2(( "GVAR " )); - if ( FT_SET_ERROR( face->goto_table( face, - TTAG_gvar, - stream, - &table_len ) ) ) + error = face->goto_table( face, + face->is_extended_glyf ? TTAG_GVAR + : TTAG_gvar, + stream, + &table_len ); + if ( FT_ERR_EQ( error, Table_Missing ) && !face->is_extended_glyf ) + { + error = face->goto_table( face, TTAG_GVAR, stream, &table_len ); + if ( !error ) + is_extended = TRUE; + } + else if ( !error && face->is_extended_glyf ) + is_extended = TRUE; + + if ( error ) { FT_TRACE2(( "is missing\n" )); goto Exit; } + header_size = is_extended ? 21 : 20; + if ( table_len < header_size ) + { + error = FT_THROW( Invalid_Table ); + goto Exit; + } + gvar_start = FT_STREAM_POS( ); if ( FT_STREAM_READ_FIELDS( gvar_fields, &gvar_head ) ) goto Exit; + if ( is_extended ) + { + if ( FT_READ_UOFF3( gvar_head.glyphCount ) ) + goto Exit; + } + else + { + FT_UShort glyph_count; + + + if ( FT_READ_USHORT( glyph_count ) ) + goto Exit; + + gvar_head.glyphCount = glyph_count; + } + + if ( FT_READ_USHORT( gvar_head.flags ) || + FT_READ_ULONG( gvar_head.offsetToData ) ) + goto Exit; + if ( gvar_head.version != 0x00010000L ) { FT_TRACE1(( "bad table version\n" )); @@ -1833,7 +1966,25 @@ goto Exit; } - if ( gvar_head.axisCount != (FT_UShort)blend->mmvar->num_axis ) + /* + * VARC can use normalized coordinates for component-internal axes in a + * static font, where 'gvar' is present without 'fvar'. Set up the + * private part of the blend machinery in that case; it deliberately has + * no `mmvar`, so the axes remain invisible through the public MM API. + */ + if ( !blend ) + { + if ( FT_SET_ERROR( tt_var_init_blend( FT_FACE( face ), + gvar_head.axisCount ) ) ) + goto Exit; + + blend = face->blend; + blend_created = TRUE; + } + + blend->gvar_is_extended = is_extended; + + if ( gvar_head.axisCount != (FT_UShort)blend->num_axis ) { FT_TRACE1(( "ft_var_load_gvar:" " number of axes in `gvar' and `cvar'\n" )); @@ -1858,7 +2009,7 @@ ( ( gvar_head.flags & 1 ) ? 4L : 2L ); /* rough sanity check */ - if (offsets_len > table_len ) + if ( offsets_len > table_len - header_size ) { FT_TRACE1(( "ft_var_load_gvar: invalid number of glyphs\n" )); error = FT_THROW( Invalid_Table ); @@ -1999,14 +2150,32 @@ gvar_head.globalCoordCount ) ) goto Fail2; - blend->tuplecount = gvar_head.globalCoordCount; + /* The tuple index in each glyph variation tuple header is only 12 */ + /* bits wide (`GX_TI_TUPLE_INDEX_MASK`), so shared tuples with a */ + /* higher index can never be referenced. Clamp the count to the */ + /* largest addressable value, `GX_TI_TUPLE_INDEX_MASK + 1`. This */ + /* also lets the fast path in `TT_Vary_Apply_Glyph_Deltas` rely on */ + /* a set tuple flag forcing the masked value out of range. */ + blend->tuplecount = + gvar_head.globalCoordCount > GX_TI_TUPLE_INDEX_MASK + 1 + ? GX_TI_TUPLE_INDEX_MASK + 1 + : gvar_head.globalCoordCount; FT_TRACE5(( "\n" )); FT_FRAME_EXIT(); } + if ( blend_created ) + { + for ( i = 0; i < blend->tuplecount; i++ ) + blend->tuplescalars[i] = (FT_Fixed)-0x20000L; + } + Exit: + if ( error && blend_created ) + tt_done_blend( FT_FACE( face ) ); + return error; Fail2: @@ -2019,6 +2188,70 @@ } + /************************************************************************** + * + * @Function: + * tt_var_init_gvar + * + * @Description: + * Initialize the private 'gvar' blend state. This also supports the + * static-font case where VARC addresses component-internal axes and no + * 'fvar' table is present. + */ + FT_LOCAL_DEF( FT_Error ) + tt_var_init_gvar( FT_Face face ) + { + TT_Face ttface = (TT_Face)face; + + + if ( ttface->blend && ttface->blend->glyphoffsets ) + return FT_Err_Ok; + + return ft_var_load_gvar( ttface ); + } + + + /************************************************************************** + * + * @Function: + * tt_var_init_blend + * + * @Description: + * Initialize a private normalized-coordinate vector without 'fvar'. + * CFF2 VARC glyphs use this with the axis count from their variation + * store; TrueType VARC glyphs get the count from 'gvar' above. + */ + FT_LOCAL_DEF( FT_Error ) + tt_var_init_blend( FT_Face face, + FT_UInt axis_count ) + { + TT_Face ttface = (TT_Face)face; + FT_Memory memory = FT_FACE_MEMORY( face ); + FT_Error error = FT_Err_Ok; + GX_Blend blend = ttface->blend; + + + if ( blend ) + return blend->num_axis == axis_count + ? FT_Err_Ok + : FT_THROW( Invalid_Table ); + + if ( FT_NEW( blend ) ) + return error; + + blend->num_axis = axis_count; + ttface->blend = blend; + + if ( FT_NEW_ARRAY( blend->normalizedcoords, axis_count ) ) + { + FT_FREE( blend ); + ttface->blend = NULL; + } + + return error; + } + + /************************************************************************** * * @Function: @@ -2507,6 +2740,11 @@ FT_FRAME_END }; + /* A static VARC face can have a private blend initialized from 'gvar' */ + /* without exposing variation axes through the public MM API. */ + if ( ttface->blend && !ttface->blend->mmvar ) + return FT_THROW( Table_Missing ); + /* `num_instances` holds the number of all named instances including */ /* the default instance, which might be missing in the table of named */ /* instances (in 'fvar'). This value is validated in `sfobjs.c` and */ @@ -3453,9 +3691,7 @@ TT_Face ttface = (TT_Face)face; FT_Error error = FT_Err_Ok; GX_Blend blend; - FT_MM_Var* mmvar; - FT_Var_Axis* a; - FT_UInt i, nc; + FT_UInt i; if ( !ttface->blend ) @@ -3474,31 +3710,30 @@ return error; } - nc = num_coords; if ( num_coords > blend->num_axis ) { FT_TRACE2(( "TT_Get_Var_Design:" " only using first %u of %u coordinates\n", blend->num_axis, num_coords )); - nc = blend->num_axis; + + FT_ARRAY_ZERO( coords + blend->num_axis, num_coords - blend->num_axis ); + num_coords = blend->num_axis; } - mmvar = blend->mmvar; - a = mmvar->axis; if ( ttface->doblend ) { - for ( i = 0; i < nc; i++, a++ ) + for ( i = 0; i < num_coords; i++ ) coords[i] = blend->coords[i]; } else { - for ( i = 0; i < nc; i++, a++ ) + FT_Var_Axis* a = blend->mmvar->axis; + + + for ( i = 0; i < num_coords; i++, a++ ) coords[i] = a->def; } - for ( ; i < num_coords; i++, a++ ) - coords[i] = a->def; - return FT_Err_Ok; } @@ -3804,7 +4039,8 @@ FT_Stream_SeekSet( stream, offsetToData ); - sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); + sharedpoints = ft_var_readpackedpoints( stream, &spoint_count, + NULL, 0 ); offsetToData = FT_Stream_FTell( stream ); @@ -3879,7 +4115,8 @@ if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) { - localpoints = ft_var_readpackedpoints( stream, &point_count ); + localpoints = ft_var_readpackedpoints( stream, &point_count, + NULL, 0 ); points = localpoints; } else @@ -3891,7 +4128,8 @@ deltas = ft_var_readpackeddeltas( stream, point_count == 0 ? face->cvt_size - : point_count ); + : point_count, + NULL, 0 ); if ( !points || !deltas ) ; /* failure, ignore it */ @@ -4025,13 +4263,13 @@ /* modeled after `af_iup_shift' */ static void - tt_delta_shift( int p1, - int p2, - int ref, + tt_delta_shift( FT_UInt p1, + FT_UInt p2, + FT_UInt ref, FT_Vector* in_points, FT_Vector* out_points ) { - int p; + FT_UInt p; FT_Vector delta; @@ -4062,14 +4300,14 @@ /* modeled after `af_iup_interp', `_iup_worker_interpolate', and */ /* `Ins_IUP' with spec differences in handling ill-defined cases. */ static void - tt_delta_interpolate( int p1, - int p2, - int ref1, - int ref2, + tt_delta_interpolate( FT_UInt p1, + FT_UInt p2, + FT_UInt ref1, + FT_UInt ref2, FT_Vector* in_points, FT_Vector* out_points ) { - int p, i; + FT_UInt p, i; FT_Pos out, in1, in2, out1, out2, d1, d2; @@ -4135,24 +4373,18 @@ FT_Vector* in_points, FT_Bool* has_delta ) { - FT_Int first_point; - FT_Int end_point; - - FT_Int first_delta; - FT_Int cur_delta; - - FT_Int point; - FT_Short contour; + FT_UInt first_point; + FT_UInt end_point; + FT_UInt first_delta; + FT_UInt cur_delta; - /* ignore empty outlines */ - if ( !outline->n_contours ) - return; + FT_UInt point; + FT_UInt contour; - contour = 0; - point = 0; - do + for ( point = 0, contour = 0; + contour < outline->n_contours; contour++ ) { end_point = outline->contours[contour]; first_point = point; @@ -4213,9 +4445,7 @@ out_points ); } } - contour++; - - } while ( contour < outline->n_contours ); + } } @@ -4269,6 +4499,8 @@ FT_UInt peak_coords_size; FT_UInt point_deltas_x_size; + FT_UInt deltas_buf_size; + FT_UInt points_buf_size; FT_UInt points_org_size; FT_UInt points_out_size; FT_UInt has_delta_size; @@ -4286,15 +4518,25 @@ FT_UInt point_count; FT_UInt spoint_count = 0; - FT_UShort* sharedpoints = NULL; - FT_UShort* localpoints = NULL; + FT_UShort* sharedpoints = NULL; + FT_UShort* localpoints = NULL; FT_UShort* points; + /* scratch buffer pool for `sharedpoints` */ + FT_UShort* shared_points_buf = NULL; + /* scratch buffer pool for `localpoints` */ + FT_UShort* local_points_buf; FT_Fixed* deltas_x = NULL; FT_Fixed* deltas_y = NULL; + /* scratch buffer pool for `deltas_x` */ + FT_Fixed* deltas_x_buf; + /* scratch buffer pool for `deltas_y` */ + FT_Fixed* deltas_y_buf; FT_Fixed* point_deltas_x = NULL; FT_Fixed* point_deltas_y = NULL; + FT_Fixed* tupleScalars; + for ( i = 0; i < n_points; i++ ) { @@ -4328,8 +4570,15 @@ /* each set of glyph variation data is formatted similarly to `cvar' */ + if ( dataSize < ( blend->gvar_is_extended ? 5U : 4U ) ) + { + error = FT_THROW( Invalid_Table ); + goto FExit; + } + tupleCount = FT_GET_USHORT(); - offsetToData = FT_GET_USHORT(); + offsetToData = blend->gvar_is_extended ? FT_GET_UOFF3() + : FT_GET_USHORT(); /* rough sanity test */ if ( offsetToData > dataSize || @@ -4344,57 +4593,62 @@ offsetToData += glyph_start; - if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) - { - here = FT_Stream_FTell( stream ); - - FT_Stream_SeekSet( stream, offsetToData ); - - sharedpoints = ft_var_readpackedpoints( stream, &spoint_count ); - - offsetToData = FT_Stream_FTell( stream ); - - FT_Stream_SeekSet( stream, here ); - } - - FT_TRACE5(( "gvar: there %s %u tuple%s:\n", - ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", - tupleCount & GX_TC_TUPLE_COUNT_MASK, - ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); - + /* Re-use a per-face scratch pool, grown on demand, instead of */ + /* allocating (and freeing) it on every glyph. This pool is freed */ + /* in `tt_done_blend`. The shared/local point-number lists are */ + /* carved out of it too, so it must be set up before they are read. */ peak_coords_size = ALIGN_SIZE( 3 * blend->num_axis * sizeof ( *peak_coords ) ); point_deltas_x_size = ALIGN_SIZE( 2 * n_points * sizeof ( *point_deltas_x ) ); + deltas_buf_size = ALIGN_SIZE( 2 * n_points * + sizeof ( *deltas_x ) ); + points_buf_size = ALIGN_SIZE( 2 * n_points * + sizeof ( *shared_points_buf ) ); points_org_size = ALIGN_SIZE( n_points * sizeof ( *points_org ) ); points_out_size = ALIGN_SIZE( n_points * sizeof ( *points_out ) ); has_delta_size = ALIGN_SIZE( n_points * sizeof ( *has_delta ) ); pool_size = peak_coords_size + point_deltas_x_size + + deltas_buf_size + + points_buf_size + points_org_size + points_out_size + has_delta_size; - if ( FT_ALLOC( pool, pool_size ) ) - goto Exit; - - p = pool; - peak_coords = (FT_Fixed*)p; - p += peak_coords_size; - point_deltas_x = (FT_Fixed*)p; - p += point_deltas_x_size; - points_org = (FT_Vector*)p; - p += points_org_size; - points_out = (FT_Vector*)p; - p += points_out_size; - has_delta = (FT_Bool*)p; + if ( pool_size > blend->glyph_delta_pool_size ) + { + if ( FT_QREALLOC( blend->glyph_delta_pool, + blend->glyph_delta_pool_size, + pool_size ) ) + goto Exit; + blend->glyph_delta_pool_size = pool_size; + } + pool = blend->glyph_delta_pool; + + p = pool; + peak_coords = (FT_Fixed*)p; + p += peak_coords_size; + point_deltas_x = (FT_Fixed*)p; + p += point_deltas_x_size; + deltas_x_buf = (FT_Fixed*)p; + p += deltas_buf_size; + shared_points_buf = (FT_UShort*)p; + p += points_buf_size; + points_org = (FT_Vector*)p; + p += points_org_size; + points_out = (FT_Vector*)p; + p += points_out_size; + has_delta = (FT_Bool*)p; FT_ARRAY_ZERO( point_deltas_x, 2 * n_points ); - im_start_coords = peak_coords + blend->num_axis; - im_end_coords = im_start_coords + blend->num_axis; - point_deltas_y = point_deltas_x + n_points; + im_start_coords = peak_coords + blend->num_axis; + im_end_coords = im_start_coords + blend->num_axis; + point_deltas_y = point_deltas_x + n_points; + deltas_y_buf = deltas_x_buf + n_points; + local_points_buf = shared_points_buf + n_points; for ( j = 0; j < n_points; j++ ) { @@ -4402,39 +4656,102 @@ points_org[j].y = FT_intToFixed( outline->points[j].y ); } - p = stream->cursor; + if ( tupleCount & GX_TC_TUPLES_SHARE_POINT_NUMBERS ) + { + here = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, offsetToData ); + + sharedpoints = ft_var_readpackedpoints( stream, &spoint_count, + shared_points_buf, n_points ); + + offsetToData = FT_Stream_FTell( stream ); + + FT_Stream_SeekSet( stream, here ); + } + + FT_TRACE5(( "gvar: there %s %u tuple%s:\n", + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "is" : "are", + tupleCount & GX_TC_TUPLE_COUNT_MASK, + ( tupleCount & GX_TC_TUPLE_COUNT_MASK ) == 1 ? "" : "s" )); + + p = stream->cursor; + tupleScalars = blend->tuplescalars; tupleCount &= GX_TC_TUPLE_COUNT_MASK; + + /* The tuple-variation headers are walked sequentially through `p`. */ + /* Each header is at least four bytes (`tupleDataSize` and */ + /* `tupleIndex`); embedded and intermediate tuples store additional */ + /* coordinate arrays after that. Bounds-check the four-byte minimum */ + /* of *all* tuples here, once, so the common path inside the loop */ + /* needs no per-tuple check. This is sound because `p` only ever */ + /* advances over these headers -- the variation data of active tuples */ + /* is read further below through a separate stream cursor -- and */ + /* `stream->limit` stays constant within the frame entered above. */ + /* Whenever a tuple consumes more than the four-byte minimum, the */ + /* embedded/intermediate branches re-check the surplus (see below). */ + if ( 4 * tupleCount > (FT_UInt)( stream->limit - p ) ) + { + FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" + " invalid glyph variation array header\n" )); + error = FT_THROW( Invalid_Table ); + goto Exit; + } + for ( i = 0; i < tupleCount; i++ ) { FT_UInt tupleDataSize; FT_UInt tupleIndex; FT_Fixed apply; - FT_Fixed* tupleScalars; FT_TRACE6(( " tuple %u:\n", i )); - tupleScalars = blend->tuplescalars; + /* The four-byte header is already covered by the up-front check. */ + tupleDataSize = FT_NEXT_USHORT( p ); + tupleIndex = FT_NEXT_USHORT( p ); - /* Enter frame for four bytes. */ - if ( 4 > stream->limit - p ) + /* Fast path for the common shared-tuple case. */ + /* */ + /* `blend->tuplecount` is clamped to `GX_TI_TUPLE_INDEX_MASK + 1` at */ + /* load time, so it is at most 0x1000. Of the tuple-index flags */ + /* only `GX_TI_PRIVATE_POINT_NUMBERS` (0x2000) may legitimately */ + /* accompany a shared-tuple index, so it is masked off here; the */ + /* embedded (0x8000), intermediate (0x4000), and reserved (0x1000) */ + /* flags each yield a value >= 0x1000 >= `blend->tuplecount', so if */ + /* any is set the comparison is false. Entering the body therefore */ + /* guarantees a plain shared tuple with an in-range index whose */ + /* scalar lives in the cache. */ + if ( ( tupleIndex & ~GX_TI_PRIVATE_POINT_NUMBERS ) + < blend->tuplecount ) { - FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" - " invalid glyph variation array header\n" )); - error = FT_THROW( Invalid_Table ); - goto Exit; - } + FT_Fixed scalar = tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK]; - tupleDataSize = FT_NEXT_USHORT( p ); - tupleIndex = FT_NEXT_USHORT( p ); - if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) - tupleScalars = NULL; + if ( scalar == 0 ) + { + offsetToData += tupleDataSize; + continue; + } + + if ( scalar != (FT_Fixed)-0x20000 ) + { + apply = scalar; + goto apply_found; + } + } if ( tupleIndex & GX_TI_EMBEDDED_TUPLE_COORD ) { - if ( 2 * blend->num_axis > (FT_UInt)( stream->limit - p ) ) + /* This tuple stores its peak coordinates inline. `p` has */ + /* advanced past the four-byte header, so the up-front check now */ + /* only accounts for the four-byte minimum of the tuples still to */ + /* come, `4 * ( tupleCount - i - 1 )`. Ensure the embedded */ + /* coordinates fit on top of that reserve; this bounds the read */ + /* and keeps the invariant intact for the following tuples. */ + if ( 2 * blend->num_axis + 4 * ( tupleCount - i - 1 ) > + (FT_UInt)( stream->limit - p ) ) { FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" " invalid glyph variation array header\n" )); @@ -4446,22 +4763,9 @@ peak_coords[j] = FT_fdot14ToFixed( FT_NEXT_SHORT( p ) ); tuple_coords = peak_coords; - tupleScalars = NULL; } else if ( ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) < blend->tuplecount ) { - FT_Fixed scalar = - tupleScalars - ? tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK] - : (FT_Fixed)-0x20000; - - - if ( scalar != (FT_Fixed)-0x20000 ) - { - apply = scalar; - goto apply_found; - } - tuple_coords = blend->tuplecoords + ( tupleIndex & GX_TI_TUPLE_INDEX_MASK ) * blend->num_axis; @@ -4477,7 +4781,12 @@ if ( tupleIndex & GX_TI_INTERMEDIATE_TUPLE ) { - if ( 4 * blend->num_axis > (FT_UInt)( stream->limit - p ) ) + /* Intermediate tuples store inline start and end coordinates, */ + /* `4 * num_axis` bytes in total. As above, check them against */ + /* the four-byte reserve of the remaining tuples so the invariant */ + /* survives into the next iteration. */ + if ( 4 * blend->num_axis + 4 * ( tupleCount - i - 1 ) > + (FT_UInt)( stream->limit - p ) ) { FT_TRACE2(( "TT_Vary_Apply_Glyph_Deltas:" " invalid glyph variation array header\n" )); @@ -4497,7 +4806,9 @@ im_start_coords, im_end_coords ); - if ( tupleScalars ) + /* Cache the scalar for shared tuples only (see fast path above). */ + if ( ( tupleIndex & ~GX_TI_PRIVATE_POINT_NUMBERS ) + < blend->tuplecount ) tupleScalars[tupleIndex & GX_TI_TUPLE_INDEX_MASK] = apply; apply_found: @@ -4514,7 +4825,8 @@ if ( tupleIndex & GX_TI_PRIVATE_POINT_NUMBERS ) { - localpoints = ft_var_readpackedpoints( stream, &point_count ); + localpoints = ft_var_readpackedpoints( stream, &point_count, + local_points_buf, n_points ); points = localpoints; } else @@ -4525,10 +4837,14 @@ deltas_x = ft_var_readpackeddeltas( stream, point_count == 0 ? n_points - : point_count ); + : point_count, + deltas_x_buf, + n_points ); deltas_y = ft_var_readpackeddeltas( stream, point_count == 0 ? n_points - : point_count ); + : point_count, + deltas_y_buf, + n_points ); if ( !points || !deltas_y || !deltas_x ) ; /* failure, ignore it */ @@ -4653,10 +4969,14 @@ #endif } - if ( localpoints != ALL_POINTS ) + /* Only free deltas that fell back to a heap allocation; */ + /* the common case reuses the pooled scratch buffers. */ + if ( localpoints != ALL_POINTS && localpoints != local_points_buf ) FT_FREE( localpoints ); - FT_FREE( deltas_x ); - FT_FREE( deltas_y ); + if ( deltas_x != deltas_x_buf ) + FT_FREE( deltas_x ); + if ( deltas_y != deltas_y_buf ) + FT_FREE( deltas_y ); offsetToData += tupleDataSize; @@ -4711,9 +5031,10 @@ } Exit: - if ( sharedpoints != ALL_POINTS ) + if ( sharedpoints != ALL_POINTS && sharedpoints != shared_points_buf ) FT_FREE( sharedpoints ); - FT_FREE( pool ); + /* The persistent per-face scratch buffer (`blend->glyph_delta_pool`) */ + /* is freed in `tt_done_blend`, not here. */ FExit: FT_FRAME_EXIT(); @@ -4793,6 +5114,9 @@ FT_FREE( itemStore->varRegionList ); } + + FT_FREE( itemStore->regionScalars ); + FT_FREE( itemStore->cachedCoords ); } @@ -4829,13 +5153,13 @@ FT_UInt i, num_axes; - /* blend->num_axis might not be set up yet */ - num_axes = blend->mmvar->num_axis; + num_axes = blend->num_axis; FT_FREE( blend->coords ); FT_FREE( blend->normalizedcoords ); FT_FREE( blend->normalized_stylecoords ); FT_FREE( blend->mmvar ); + FT_FREE( blend->glyph_delta_pool ); if ( blend->avar_table ) { @@ -4888,6 +5212,9 @@ FT_FREE( blend->tuplecoords ); FT_FREE( blend->glyphoffsets ); FT_FREE( blend ); + + /* the face may outlive its blend (e.g., after a failed setup) */ + ttface->blend = NULL; } } diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h index 8a59c0cd6e60..c8446e134b28 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttgxvar.h @@ -262,6 +262,10 @@ FT_BEGIN_HEADER * gv_glyphcnt :: * The number of glyphs handled in the `gvar' table. * + * gvar_is_extended :: + * A boolean which is set when glyph variation data comes from the + * 'GVAR' table (instead of 'gvar'). + * * glyphoffsets :: * Offsets into the glyph variation data array. * @@ -300,10 +304,16 @@ FT_BEGIN_HEADER FT_Fixed* tuplescalars; /* tuplescalars[tuplecount] */ FT_UInt gv_glyphcnt; + FT_Bool gvar_is_extended; FT_ULong* glyphoffsets; /* glyphoffsets[gv_glyphcnt + 1] */ FT_ULong gvar_size; + /* Scratch pool reused across glyphs by `TT_Vary_Apply_Glyph_Deltas`, */ + /* grown on demand, to avoid per-glyph/per-tuple heap allocations. */ + FT_Byte* glyph_delta_pool; + FT_ULong glyph_delta_pool_size; + } GX_BlendRec; @@ -443,6 +453,13 @@ FT_BEGIN_HEADER FT_Fixed* *normalizedcoords, FT_MM_Var* *mm_var ); + FT_LOCAL( FT_Error ) + tt_var_init_gvar( FT_Face face ); + + FT_LOCAL( FT_Error ) + tt_var_init_blend( FT_Face face, + FT_UInt axis_count ); + FT_LOCAL( void ) tt_done_blend( FT_Face face ); diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c index f850bc418e7b..cc99b2ebd42e 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.c @@ -1104,7 +1104,7 @@ /* documentation is in freetype.h */ static __inline FT_Int32 - TT_MulFixi14_i386( FT_Int32 a, + TT_MulFix14_i386( FT_Int32 a, FT_Int32 b ) { FT_Int32 result; @@ -1499,7 +1499,9 @@ * * @Note: * See `ttinterp.h' for details on backward compatibility mode. - * `Touches' the point. + * `Touches' the point. When both freedom and projection vectors + * are aligned along the axes, the moves are handled by simplified + * versions of this function; more complex moves are handled here. */ static void Direct_Move( TT_ExecContext exc, @@ -1514,10 +1516,10 @@ if ( v != 0 ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - /* Exception to the post-IUP curfew: Allow the x component of */ - /* diagonal moves, but only post-IUP. DejaVu tries to adjust */ - /* diagonal stems like on `Z' and `z' post-IUP. */ - if ( !exc->backward_compatibility ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + /* Exception for horizontal projection is made for Comic Sans MS. */ + if ( !exc->backward_compatibility || + exc->GS.projVector.y == 0 ) #endif zone->cur[point].x = ADD_LONG( zone->cur[point].x, FT_MulFix( distance, v ) ); @@ -1529,8 +1531,10 @@ if ( v != 0 ) { #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL - /* See `ttinterp.h' for details on backward compatibility mode. */ - if ( exc->backward_compatibility != 0x7 ) + /* See `ttinterp.h' for details on backward compatibility mode. */ + /* Exception for horizontal projection is made for Comic Sans MS. */ + if ( exc->backward_compatibility != 0x7 || + exc->GS.projVector.y == 0 ) #endif zone->cur[point].y = ADD_LONG( zone->cur[point].y, FT_MulFix( distance, v ) ); @@ -1660,6 +1664,27 @@ zone->org[point].y = ADD_LONG( zone->org[point].y, distance ); } + +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + + static void + Update_Native_ClearType_X_State( TT_ExecContext exc ) + { + /* `backward_compatibility' is also zero in v35, the CVT program, */ + /* monochrome rendering, and tricky-font execution. */ + exc->native_cleartype_x = FT_BOOL( + !exc->backward_compatibility && + exc->GS.projVector.y == 0 && + exc->GS.freeVector.y == 0 && + SUBPIXEL_HINTING_MINIMAL && + exc->iniRange == tt_coderange_glyph && + exc->mode != FT_RENDER_MODE_MONO && + !FT_IS_TRICKY( (FT_Face)exc->face ) ); + } + +#endif /* TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL */ + + /************************************************************************** * * @Function: @@ -2250,9 +2275,12 @@ exc->moveVector.x = exc->GS.freeVector.x * 4; exc->moveVector.y = exc->GS.freeVector.y * 4; } - else if ( -0x400L < F_dot_P && F_dot_P < 0x400L ) + else if ( -0x1555L < F_dot_P && F_dot_P < 0x1555L ) { - /* prohibitively orthogonal */ + /* prohibitively near-orthogonal; the empirical limit avoids */ + /* bad rendering in Palatino without negative consequences */ + FT_TRACE3(( "F_dot_P = %.2f, too small for valid movement.\n", + F_dot_P / 16384.)); exc->moveVector.x = 0; exc->moveVector.y = 0; } @@ -2292,6 +2320,12 @@ else exc->func_dualproj = (TT_Project_Func)Dual_Project; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Projection/freedom-vector changes can enter or leave the */ + /* native ClearType direction. */ + Update_Native_ClearType_X_State( exc ); +#endif + /* Disable cached aspect ratio */ exc->tt_metrics.ratio = 0; } @@ -2841,7 +2875,13 @@ ARRAY_BOUND_ERROR; } else + { + Modify_CVT_Check( exc ); + if ( exc->error ) + return; + exc->cvt[I] = FT_MulFix( args[1], exc->tt_metrics.scale ); + } } @@ -2908,8 +2948,19 @@ Ins_ROUND( TT_ExecContext exc, FT_Long* args ) { - args[0] = exc->func_round( exc, args[0], - exc->GS.compensation[exc->opcode & 3] ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* + * Native ClearType applies ROUND to the 1/16-pixel virtual + * grid in the ClearType direction. Approximate this in v40 + * by leaving the result unrounded. + */ + if ( exc->native_cleartype_x ) + args[0] = Round_None( exc, args[0], + exc->GS.compensation[exc->opcode & 3] ); + else +#endif + args[0] = exc->func_round( exc, args[0], + exc->GS.compensation[exc->opcode & 3] ); } @@ -4722,7 +4773,13 @@ /* compatibility hacks and lets them program points to the grid like */ /* it's 1996. They might sign a waiver for just one glyph, though. */ if ( SUBPIXEL_HINTING_MINIMAL ) + { exc->backward_compatibility = ( L & 4 ) ^ 4; + + /* A glyph can temporarily switch between backward-compatible */ + /* and native ClearType, so update the native-X state too. */ + Update_Native_ClearType_X_State( exc ); + } #endif } else if ( exc->pedantic_hinting ) @@ -4923,37 +4980,38 @@ Compute_Point_Displacement( TT_ExecContext exc, FT_F26Dot6* x, FT_F26Dot6* y, - TT_GlyphZone zone, - FT_UShort* refp ) + FT_Vector* cur, + FT_UInt* refp ) { - TT_GlyphZoneRec zp; - FT_UShort p; - FT_F26Dot6 d; + TT_GlyphZone zp; + FT_UShort p; + FT_F26Dot6 d; if ( exc->opcode & 1 ) { - zp = exc->zp0; + zp = &exc->zp0; p = exc->GS.rp1; } else { - zp = exc->zp1; + zp = &exc->zp1; p = exc->GS.rp2; } - if ( BOUNDS( p, zp.n_points ) ) + if ( BOUNDS( p, zp->n_points ) ) { if ( exc->pedantic_hinting ) exc->error = FT_THROW( Invalid_Reference ); - *refp = 0; return FAILURE; } - *zone = zp; - *refp = p; + /* return reference if zones match */ + if ( refp ) + *refp = cur == zp->cur ? p + : ~0U; /* nan */ - d = PROJECT( zp.cur + p, zp.org + p ); + d = PROJECT( zp->cur + p, zp->org + p ); *x = FT_MulFix( d, exc->moveVector.x ); *y = FT_MulFix( d, exc->moveVector.y ); @@ -4965,10 +5023,9 @@ /* See `ttinterp.h' for details on backward compatibility mode. */ static void Move_Zp2_Point( TT_ExecContext exc, - FT_UShort point, + FT_UInt point, FT_F26Dot6 dx, - FT_F26Dot6 dy, - FT_Bool touch ) + FT_F26Dot6 dy ) { if ( exc->GS.freeVector.x != 0 ) { @@ -4978,8 +5035,7 @@ #endif exc->zp2.cur[point].x = ADD_LONG( exc->zp2.cur[point].x, dx ); - if ( touch ) - exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; + exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_X; } if ( exc->GS.freeVector.y != 0 ) @@ -4990,8 +5046,7 @@ #endif exc->zp2.cur[point].y = ADD_LONG( exc->zp2.cur[point].y, dy ); - if ( touch ) - exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; + exc->zp2.tags[point] |= FT_CURVE_TAG_TOUCH_Y; } } @@ -5007,11 +5062,9 @@ FT_Long* args ) { FT_Long loop = exc->GS.loop; - TT_GlyphZoneRec zp; - FT_UShort refp; FT_F26Dot6 dx, dy; - FT_UShort point; + FT_UInt point; if ( exc->new_top < loop ) @@ -5023,12 +5076,12 @@ exc->new_top -= loop; - if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) + if ( Compute_Point_Displacement( exc, &dx, &dy, NULL, NULL ) ) return; while ( loop-- ) { - point = (FT_UShort)*(--args); + point = (FT_UInt)*(--args); if ( BOUNDS( point, exc->zp2.n_points ) ) { @@ -5039,7 +5092,7 @@ } } else - Move_Zp2_Point( exc, point, dx, dy, TRUE ); + Move_Zp2_Point( exc, point, dx, dy ); } Fail: @@ -5061,12 +5114,10 @@ Ins_SHC( TT_ExecContext exc, FT_Long* args ) { - TT_GlyphZoneRec zp; - FT_UShort refp; + FT_UInt refp, start, limit, i; FT_F26Dot6 dx, dy; FT_UShort contour, bounds; - FT_UShort start, limit, i; contour = (FT_UShort)args[0]; @@ -5079,7 +5130,7 @@ return; } - if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) + if ( Compute_Point_Displacement( exc, &dx, &dy, exc->zp2.cur, &refp ) ) return; if ( contour == 0 ) @@ -5095,8 +5146,8 @@ for ( i = start; i < limit; i++ ) { - if ( zp.cur != exc->zp2.cur || refp != i ) - Move_Zp2_Point( exc, i, dx, dy, TRUE ); + if ( refp != i ) + Move_Zp2_Point( exc, i, dx, dy ); } } @@ -5111,40 +5162,59 @@ Ins_SHZ( TT_ExecContext exc, FT_Long* args ) { - TT_GlyphZoneRec zp; - FT_UShort refp; - FT_F26Dot6 dx, - dy; - - FT_UShort limit, i; + FT_Vector* cur; + FT_UInt refp, i, limit; + FT_F26Dot6 dx, dy; - if ( BOUNDS( args[0], 2 ) ) + /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points, */ + /* which must be subtracted. */ + switch ( (FT_Int)args[0] ) { + case 0: + cur = exc->twilight.cur; + limit = exc->twilight.n_points; + break; + + case 1: + cur = exc->pts.cur; + limit = exc->pts.n_points > 4U ? exc->pts.n_points - 4U : 0; + break; + + default: if ( exc->pedantic_hinting ) exc->error = FT_THROW( Invalid_Reference ); return; } - if ( Compute_Point_Displacement( exc, &dx, &dy, &zp, &refp ) ) + if ( Compute_Point_Displacement( exc, &dx, &dy, cur, &refp ) ) return; - /* XXX: UNDOCUMENTED! SHZ doesn't move the phantom points. */ - /* Twilight zone has no real contours, so use `n_points'. */ - /* Normal zone's `n_points' includes phantoms, so must */ - /* use end of last contour. */ - if ( exc->GS.gep2 == 0 ) - limit = exc->zp2.n_points; - else if ( exc->GS.gep2 == 1 && exc->zp2.n_contours > 0 ) - limit = exc->zp2.contours[exc->zp2.n_contours - 1] + 1; - else - limit = 0; + /* XXX: UNDOCUMENTED! SHZ doesn't touch the points. */ + if ( dx ) + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( !exc->backward_compatibility ) +#endif + for ( i = 0; i < limit; i++ ) + { + if ( refp != i ) + cur[i].x = ADD_LONG( cur[i].x, dx ); + } + } - /* XXX: UNDOCUMENTED! SHZ doesn't touch the points */ - for ( i = 0; i < limit; i++ ) + if ( dy ) { - if ( zp.cur != exc->zp2.cur || refp != i ) - Move_Zp2_Point( exc, i, dx, dy, FALSE ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* See `ttinterp.h' for details on backward compatibility mode. */ + if ( exc->backward_compatibility != 0x7 ) +#endif + for ( i = 0; i < limit; i++ ) + { + if ( refp != i ) + cur[i].y = ADD_LONG( cur[i].y, dy ); + } } } @@ -5161,7 +5231,7 @@ { FT_Long loop = exc->GS.loop; FT_F26Dot6 dx, dy; - FT_UShort point; + FT_UInt point; #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL FT_Bool in_twilight = FT_BOOL( exc->GS.gep0 == 0 || exc->GS.gep1 == 0 || @@ -5183,7 +5253,7 @@ while ( loop-- ) { - point = (FT_UShort)*(--args); + point = (FT_UInt)*(--args); if ( BOUNDS( point, exc->zp2.n_points ) ) { @@ -5206,11 +5276,11 @@ ( exc->backward_compatibility != 0x7 && ( ( exc->is_composite && exc->GS.freeVector.y != 0 ) || ( exc->zp2.tags[point] & FT_CURVE_TAG_TOUCH_Y ) ) ) ) - Move_Zp2_Point( exc, point, 0, dy, TRUE ); + Move_Zp2_Point( exc, point, 0, dy ); } else #endif - Move_Zp2_Point( exc, point, dx, dy, TRUE ); + Move_Zp2_Point( exc, point, dx, dy ); } Fail: @@ -5293,7 +5363,12 @@ if ( ( exc->opcode & 1 ) != 0 ) { cur_dist = FAST_PROJECT( &exc->zp0.cur[point] ); - distance = SUB_LONG( exc->func_round( exc, cur_dist, 0 ), cur_dist ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( exc->native_cleartype_x ) + distance = 0; + else +#endif + distance = SUB_LONG( exc->func_round( exc, cur_dist, 0 ), cur_dist ); } else distance = 0; @@ -5371,6 +5446,13 @@ FT_F26Dot6 delta; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Native ClearType reduces CVT cut-in to 1/16 in the */ + /* ClearType direction. */ + if ( exc->native_cleartype_x ) + control_value_cutin >>= 4; +#endif + delta = SUB_LONG( distance, org_dist ); if ( delta < 0 ) delta = NEG_LONG( delta ); @@ -5378,7 +5460,10 @@ if ( delta > control_value_cutin ) distance = org_dist; - distance = exc->func_round( exc, distance, 0 ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( !exc->native_cleartype_x ) +#endif + distance = exc->func_round( exc, distance, 0 ); } exc->func_move( exc, &exc->zp0, point, SUB_LONG( distance, org_dist ) ); @@ -5472,7 +5557,14 @@ compensation = exc->GS.compensation[exc->opcode & 3]; if ( ( exc->opcode & 4 ) != 0 ) - distance = exc->func_round( exc, org_dist, compensation ); + { +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( exc->native_cleartype_x ) + distance = Round_None( exc, org_dist, compensation ); + else +#endif + distance = exc->func_round( exc, org_dist, compensation ); + } else distance = Round_None( exc, org_dist, compensation ); @@ -5483,6 +5575,13 @@ FT_F26Dot6 minimum_distance = exc->GS.minimum_distance; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Native ClearType reduces minimum distance to 1/2 in the */ + /* ClearType direction. */ + if ( exc->native_cleartype_x ) + minimum_distance >>= 1; +#endif + if ( org_dist >= 0 ) { if ( distance < minimum_distance ) @@ -5605,6 +5704,13 @@ FT_F26Dot6 control_value_cutin = exc->GS.control_value_cutin; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Native ClearType reduces CVT cut-in to 1/16 in the */ + /* ClearType direction. */ + if ( exc->native_cleartype_x ) + control_value_cutin >>= 4; +#endif + /* XXX: According to Greg Hitchcock, the following wording is */ /* the right one: */ /* */ @@ -5625,7 +5731,12 @@ cvt_dist = org_dist; } - distance = exc->func_round( exc, cvt_dist, compensation ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + if ( exc->native_cleartype_x ) + distance = Round_None( exc, cvt_dist, compensation ); + else +#endif + distance = exc->func_round( exc, cvt_dist, compensation ); } else distance = Round_None( exc, cvt_dist, compensation ); @@ -5637,6 +5748,13 @@ FT_F26Dot6 minimum_distance = exc->GS.minimum_distance; +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + /* Native ClearType reduces minimum distance to 1/2 in the */ + /* ClearType direction. */ + if ( exc->native_cleartype_x ) + minimum_distance >>= 1; +#endif + if ( org_dist >= 0 ) { if ( distance < minimum_distance ) @@ -6191,14 +6309,14 @@ IUP_WorkerRec V; FT_Byte mask; - FT_UInt first_point; /* first point of contour */ - FT_UInt end_point; /* end point (last+1) of contour */ + FT_UInt first_point; /* first point of contour */ + FT_UInt end_point; /* end point (last+1) of contour */ - FT_UInt first_touched; /* first touched point in contour */ - FT_UInt cur_touched; /* current touched point in contour */ + FT_UInt first_touched; /* first touched point in contour */ + FT_UInt cur_touched; /* current touched point in contour */ - FT_UInt point; /* current point */ - FT_Short contour; /* current contour */ + FT_UInt point; /* current point */ + FT_UInt contour; /* current contour */ #ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL @@ -6566,11 +6684,23 @@ * Selector Bit: 11 * Return Bit(s): 18 * - * The only smoothing method FreeType supports unless someone sets - * FT_LOAD_TARGET_MONO. + * Report the smoothing mode selected by the DirectWrite-style + * ClearType policy for this face and PPEM. */ - if ( ( args[0] & 2048 ) != 0 && exc->mode != FT_RENDER_MODE_MONO ) - K |= 1 << 18; + if ( ( args[0] & 2048 ) != 0 && + exc->mode != FT_RENDER_MODE_MONO ) + { + FT_Bool symmetric_smoothing; + + + tt_face_get_cleartype_policy( exc->face, + exc->metrics.y_ppem, + &symmetric_smoothing, + NULL ); + + if ( symmetric_smoothing ) + K |= 1 << 18; + } /********************************* * CLEARTYPE HINTING AND @@ -7339,56 +7469,11 @@ } if ( exc->error ) - { - switch ( exc->error ) - { - case FT_ERR( Invalid_Opcode ): - { - TT_DefRecord* def = exc->IDefs; - TT_DefRecord* limit = FT_OFFSET( def, exc->numIDefs ); - - - /* looking for redefined instructions */ - for ( ; def < limit; def++ ) - { - if ( def->active && exc->opcode == (FT_Byte)def->opc ) - { - TT_CallRec* callrec; - - - if ( exc->callTop >= exc->callSize ) - { - exc->error = FT_THROW( Invalid_Reference ); - goto LErrorLabel_; - } - - callrec = &exc->callStack[exc->callTop]; - - callrec->Caller_Range = exc->curRange; - callrec->Caller_IP = exc->IP + 1; - callrec->Cur_Count = 1; - callrec->Def = def; - - if ( Ins_Goto_CodeRange( exc, - def->range, - def->start ) == FAILURE ) - goto LErrorLabel_; - - goto LSuiteLabel_; - } - } - } - FALL_THROUGH; - - default: - goto LErrorLabel_; - } - } + goto LErrorLabel_; exc->top = exc->new_top; exc->IP += exc->length; - LSuiteLabel_: if ( exc->IP >= exc->codeSize ) { if ( exc->callTop > 0 ) diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h index 05ac831dfd13..5b71bb82d805 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttinterp.h @@ -378,6 +378,14 @@ FT_BEGIN_HEADER * */ + /* + * Native ClearType horizontal execution state. Microsoft ClearType + * uses a 1/16-pixel grid in the ClearType direction; version 40 + * approximates this by leaving rounded horizontal point moves + * unrounded. + */ + FT_Bool native_cleartype_x; + /* Activate backward compatibility (bit 2) and track IUP (bits 0-1). */ /* If this is zero, it means that the interpreter is either in v35 */ /* or in native ClearType mode. */ diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c index dc897688584a..8c76e23dbf81 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.c @@ -21,6 +21,7 @@ #include #include #include +#include #include "ttgload.h" #include "ttpload.h" @@ -852,11 +853,74 @@ #ifdef TT_CONFIG_OPTION_GX_VAR_SUPPORT tt_done_blend( ttface ); - face->blend = NULL; #endif } +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + + FT_LOCAL_DEF( void ) + tt_face_get_cleartype_policy( TT_Face face, + FT_UInt ppem, + FT_Bool* symmetric_smoothing, + FT_Bool* grid_fit ) + { + FT_Bool symmetric; + FT_Bool fit; + FT_Bool found = FALSE; + FT_UShort flags = 0; + FT_UInt i; + + + /* + * DirectWrite fallback for hinted fonts without an applicable + * version-1 ClearType 'gasp' range: + * + * <= 20 ppem NATURAL + * > 20 ppem NATURAL_SYMMETRIC + * + * Fonts without glyph bytecode use symmetric rendering. + * + * `maxSizeOfInstructions` is also what Skia uses to determine + * whether a TrueType face is hinted for this DirectWrite policy. + */ + fit = FT_BOOL( face->max_profile.maxSizeOfInstructions != 0 ); + + symmetric = FT_BOOL( !fit || ppem > 20 ); + + /* + * A valid version-1 `gasp' range explicitly controls the two + * independent ClearType properties. + */ + if ( face->gasp.version >= 1 ) + { + for ( i = 0; i < face->gasp.numRanges; i++ ) + { + if ( ppem <= face->gasp.gaspRanges[i].maxPPEM ) + { + flags = face->gasp.gaspRanges[i].gaspFlag; + found = TRUE; + break; + } + } + + if ( found ) + { + symmetric = FT_BOOL( flags & FT_GASP_SYMMETRIC_SMOOTHING ); + fit = FT_BOOL( flags & FT_GASP_SYMMETRIC_GRIDFIT ); + } + } + + if ( symmetric_smoothing ) + *symmetric_smoothing = symmetric; + + if ( grid_fit ) + *grid_fit = fit; + } + +#endif + + /************************************************************************** * * SIZE FUNCTIONS @@ -909,15 +973,15 @@ error = TT_Run_Context( exec, size ); FT_TRACE4(( error ? " failed (error code 0x%x)\n" : "", error )); + + if ( !error ) + TT_Save_Context( exec, size ); } else error = FT_Err_Ok; size->bytecode_ready = error; - if ( !error ) - TT_Save_Context( exec, size ); - return error; } @@ -990,15 +1054,15 @@ error = TT_Run_Context( exec, size ); FT_TRACE4(( error ? " failed (error code 0x%x)\n" : "", error )); + + if ( !error ) + TT_Save_Context( exec, size ); } else error = FT_Err_Ok; size->cvt_ready = error; - if ( !error ) - TT_Save_Context( exec, size ); - return error; } diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h index 9b2f412ac475..01e581e1c1a1 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttobjs.h @@ -325,6 +325,22 @@ FT_BEGIN_HEADER tt_slot_init( FT_GlyphSlot slot ); +#ifdef TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL + + /* + * Return the DirectWrite-style ClearType policy for a face and PPEM. + * + * Either output pointer may be NULL. + */ + FT_LOCAL( void ) + tt_face_get_cleartype_policy( TT_Face face, + FT_UInt ppem, + FT_Bool* symmetric_smoothing, + FT_Bool* grid_fit ); + +#endif + + /* auxiliary */ #define IS_HINTED( flags ) ( ( flags & FT_LOAD_NO_HINTING ) == 0 ) diff --git a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c index 5b0a3944d6a7..ec85f48ce2c2 100644 --- a/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c +++ b/src/java.desktop/share/native/libfreetype/src/truetype/ttpload.c @@ -69,7 +69,11 @@ /* we need the size of the `glyf' table for malformed `loca' tables */ - error = face->goto_table( face, TTAG_glyf, stream, &face->glyf_len ); + error = face->goto_table( face, + face->is_extended_glyf ? TTAG_GLYF + : TTAG_glyf, + stream, + &face->glyf_len ); /* it is possible that a font doesn't have a glyf table at all */ /* or its size is zero */ @@ -91,7 +95,11 @@ } FT_TRACE2(( "Locations " )); - error = face->goto_table( face, TTAG_loca, stream, &table_len ); + error = face->goto_table( face, + face->is_extended_glyf ? TTAG_LOCA + : TTAG_loca, + stream, + &table_len ); if ( error ) { error = FT_THROW( Locations_Missing ); @@ -100,7 +108,8 @@ shift = face->header.Index_To_Loc_Format != 0 ? 2 : 1; - if ( table_len > 0x10000UL << shift ) + if ( !face->is_extended_glyf && + table_len > 0x10000UL << shift ) { FT_TRACE2(( "table too large\n" )); table_len = 0x10000UL << shift; diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1load.c b/src/java.desktop/share/native/libfreetype/src/type1/t1load.c index 1d095f8ac1f8..2ed327ba2e75 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1load.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1load.c @@ -677,7 +677,7 @@ PS_Blend blend = t1face->blend; FT_Fixed axiscoords[4]; - FT_UInt i, nc; + FT_UInt i; if ( !blend ) @@ -687,19 +687,18 @@ axiscoords, blend->num_axis ); - nc = num_coords; if ( num_coords > blend->num_axis ) { FT_TRACE2(( "T1_Get_Var_Design:" " only using first %u of %u coordinates\n", blend->num_axis, num_coords )); - nc = blend->num_axis; + + FT_ARRAY_ZERO( coords + blend->num_axis, num_coords - blend->num_axis ); + num_coords = blend->num_axis; } - for ( i = 0; i < nc; i++ ) + for ( i = 0; i < num_coords; i++ ) coords[i] = mm_axis_unmap( &blend->design_map[i], axiscoords[i] ); - for ( ; i < num_coords; i++ ) - coords[i] = 0; return FT_Err_Ok; } diff --git a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c index a9b8d18a6ff6..73bfb0cdecce 100644 --- a/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c +++ b/src/java.desktop/share/native/libfreetype/src/type1/t1parse.c @@ -268,33 +268,34 @@ if ( parser->in_pfb ) { - /* in the case of the PFB format, the private dictionary can be */ - /* made of several segments. We thus first read the number of */ - /* segments to compute the total size of the private dictionary */ - /* then re-read them into memory. */ - FT_ULong start_pos = FT_STREAM_POS(); + /* in the case of the PFB format, the private dictionary can be */ + /* made of several adjacent segments. */ FT_UShort tag; + FT_Byte* priv_dict = NULL; + FT_ULong priv_len = 0; - parser->private_len = 0; for (;;) { error = read_pfb_tag( stream, &tag, &size ); if ( error ) - goto Fail; + break; - if ( tag != 0x8002U ) + if ( tag != 0x8002U || size > stream->size - stream->pos ) break; - parser->private_len += size; + if ( FT_QREALLOC( priv_dict, priv_len, priv_len + size ) || + FT_STREAM_READ( priv_dict + priv_len, size ) ) + break; - if ( FT_STREAM_SKIP( size ) ) - goto Fail; + priv_len += size; } + parser->private_dict = priv_dict; + parser->private_len = priv_len; + /* Check that we have a private dictionary there */ - /* and allocate private dictionary buffer */ - if ( parser->private_len == 0 ) + if ( priv_len == 0 ) { FT_ERROR(( "T1_Get_Private_Dict:" " invalid private dictionary section\n" )); @@ -302,26 +303,8 @@ goto Fail; } - if ( FT_STREAM_SEEK( start_pos ) || - FT_QALLOC( parser->private_dict, parser->private_len ) ) - goto Fail; - - parser->private_len = 0; - for (;;) - { - error = read_pfb_tag( stream, &tag, &size ); - if ( error || tag != 0x8002U ) - { - error = FT_Err_Ok; - break; - } - - if ( FT_STREAM_READ( parser->private_dict + parser->private_len, - size ) ) - goto Fail; - - parser->private_len += size; - } + /* discard any errors from truncated files */ + error = FT_Err_Ok; } else { @@ -339,11 +322,8 @@ FT_Bool test_cr; - parser->root.cursor = parser->base_dict; - parser->root.limit = parser->base_dict + parser->base_len; - - cur = parser->root.cursor; - limit = parser->root.limit; + parser->root.cursor = cur; + parser->root.limit = limit; while ( cur < limit ) { diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageAffine.h b/src/java.desktop/share/native/libmlib_image/mlib_ImageAffine.h index 567d8f3491ec..1687b4528782 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageAffine.h +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageAffine.h @@ -28,7 +28,6 @@ #define __MLIB_IMAGEAFFINE_H #include "mlib_image.h" -#include "mlib_ImageDivTables.h" #include "mlib_ImageFilters.h" #ifdef __cplusplus diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageAffineEdge.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageAffineEdge.c index 2cb39d0b55ad..91d5f50e566b 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageAffineEdge.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageAffineEdge.c @@ -84,7 +84,7 @@ #define MLIB_SIGN_SHIFT 31 /***************************************************************/ -#define D64mlib_u8(X) mlib_U82D64[X] +#define D64mlib_u8(X) ((mlib_d64)(X)) #define D64mlib_s16(X) ((mlib_d64)(X)) #define D64mlib_u16(X) ((mlib_d64)(X)) #define D64mlib_s32(X) ((mlib_d64)(X)) diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv.h b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv.h index b3e7a2b3d5ee..cd87e8f06145 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv.h +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv.h @@ -39,24 +39,6 @@ if (k != akernel) mlib_free(k); \ return status #endif /* FREE_AND_RETURN_STATUS */ -mlib_status mlib_convMxNnw_d64(mlib_image *dst, - const mlib_image *src, - const mlib_d64 *ker, - mlib_s32 m, - mlib_s32 n, - mlib_s32 dm, - mlib_s32 dn, - mlib_s32 cmask); - -mlib_status mlib_convMxNnw_f32(mlib_image *dst, - const mlib_image *src, - const mlib_d64 *ker, - mlib_s32 m, - mlib_s32 n, - mlib_s32 dm, - mlib_s32 dn, - mlib_s32 cmask); - mlib_status mlib_convMxNnw_s16(mlib_image *dst, const mlib_image *src, const mlib_s32 *kernel, diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvClearEdge_Fp.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvClearEdge_Fp.c deleted file mode 100644 index e26ed8389ce0..000000000000 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvClearEdge_Fp.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2003, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - - -/* - * FUNCTIONS - * mlib_c_ImageConvClearEdge - Set edge of an image to a specific - * color. (for float-point image) - * - * SYNOPSIS - * mlib_status mlib_c_ImageConvClearEdge_Fp(mlib_image *img, - * mlib_s32 dx_l, - * mlib_s32 dx_r, - * mlib_s32 dy_t, - * mlib_s32 dy_b, - * const mlib_d64 *color, - * mlib_s32 cmask) - * - * ARGUMENT - * img Pointer to an image. - * dx_l Number of columns on the left side of the - * image to be cleared. - * dx_r Number of columns on the right side of the - * image to be cleared. - * dy_t Number of rows on the top edge of the - * image to be cleared. - * dy_b Number of rows on the top edge of the - * image to be cleared. - * color Pointer to the color that the edges are set to. - * cmask Channel mask to indicate the channels to be convolved. - * Each bit of which represents a channel in the image. The - * channels corresponded to 1 bits are those to be processed. - * - * RESTRICTION - * img can have 1, 2, 3 or 4 channels of MLIB_FLOAT or MLIB_DOUBLE - * data type. - * - * DESCRIPTION - * Set edge of an image to a specific color. - * The unselected channels are not overwritten. - * If src and dst have just one channel, - * cmask is ignored. - */ - -#include "mlib_image.h" -#include "mlib_ImageConvEdge.h" - -/***************************************************************/ -#define EDGES(chan, type, mask) \ -{ \ - type *pimg = (type *) mlib_ImageGetData(img); \ - type color_i; \ - mlib_s32 img_stride = mlib_ImageGetStride(img) / sizeof(type); \ - mlib_s32 i, j, l; \ - mlib_s32 testchan; \ - \ - testchan = 1; \ - for (l = chan - 1; l >= 0; l--) { \ - if ((mask & testchan) == 0) { \ - testchan <<= 1; \ - continue; \ - } \ - testchan <<= 1; \ - color_i = (type) color[l]; \ - for (j = 0; j < dx_l; j++) { \ - for (i = dy_t; i < (img_height - dy_b); i++) { \ - pimg[i * img_stride + l + j * chan] = color_i; \ - } \ - } \ - for (j = 0; j < dx_r; j++) { \ - for (i = dy_t; i < (img_height - dy_b); i++) { \ - pimg[i * img_stride + l + (img_width - 1 - j) * chan] = color_i; \ - } \ - } \ - for (i = 0; i < dy_t; i++) { \ - for (j = 0; j < img_width; j++) { \ - pimg[i * img_stride + l + j * chan] = color_i; \ - } \ - } \ - for (i = 0; i < dy_b; i++) { \ - for (j = 0; j < img_width; j++) { \ - pimg[(img_height - 1 - i) * img_stride + l + j * chan] = color_i; \ - } \ - } \ - } \ -} - -/***************************************************************/ -mlib_status mlib_ImageConvClearEdge_Fp(mlib_image *img, - mlib_s32 dx_l, - mlib_s32 dx_r, - mlib_s32 dy_t, - mlib_s32 dy_b, - const mlib_d64 *color, - mlib_s32 cmask) -{ - mlib_s32 img_width = mlib_ImageGetWidth(img); - mlib_s32 img_height = mlib_ImageGetHeight(img); - mlib_s32 channel = mlib_ImageGetChannels(img); - - if (dx_l + dx_r > img_width) { - dx_l = img_width; - dx_r = 0; - } - - if (dy_t + dy_b > img_height) { - dy_t = img_height; - dy_b = 0; - } - - if (channel == 1) cmask = 1; - - switch (mlib_ImageGetType(img)) { - case MLIB_FLOAT: - EDGES(channel,mlib_f32, cmask); - break; - case MLIB_DOUBLE: - EDGES(channel,mlib_d64, cmask); - break; - default: - return MLIB_FAILURE; - } - - return MLIB_SUCCESS; -} - -/***************************************************************/ diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvEdge.h b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvEdge.h index 7aaabfcc20b3..0bd8ecfd240d 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvEdge.h +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvEdge.h @@ -47,14 +47,6 @@ mlib_status mlib_ImageConvClearEdge(mlib_image *dst, const mlib_s32 *color, mlib_s32 cmask); -mlib_status mlib_ImageConvClearEdge_Fp(mlib_image *img, - mlib_s32 dx_l, - mlib_s32 dx_r, - mlib_s32 dy_t, - mlib_s32 dy_b, - const mlib_d64 *color, - mlib_s32 cmask); - mlib_status mlib_ImageConvZeroEdge(mlib_image *dst, mlib_s32 dx_l, mlib_s32 dx_r, diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c index 7723b3c6191c..8554d78e5e61 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c @@ -196,19 +196,8 @@ mlib_status mlib_ImageConvMxN_f(mlib_image *dst, case MLIB_INT: ret = mlib_convMxNnw_s32(dst_i, src_i, kernel, m, n, dm, dn, scale, cmask); break; - case MLIB_FLOAT: - ret = mlib_convMxNnw_f32(dst_i, src_i, kernel, m, n, dm, dn, cmask); - break; - case MLIB_DOUBLE: - ret = mlib_convMxNnw_d64(dst_i, src_i, kernel, m, n, dm, dn, cmask); - break; - default: - /* For some reasons, there is no convolution routine for type MLIB_BIT. - * For now, we silently ignore it (because this image type is not used by java), - * but probably we have to report an error. - */ - break; + return MLIB_FAILURE; } } diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c deleted file mode 100644 index 11d7e9d3387f..000000000000 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN_Fp.c +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - - -/* - * FUNCTION - * mlib_ImageConvMxN_Fp - image convolution with edge condition - * - * SYNOPSIS - * mlib_status mlib_ImageConvMxN_Fp(mlib_image *dst, - * const mlib_image *src, - * const mlib_d64 *kernel, - * mlib_s32 m, - * mlib_s32 n, - * mlib_s32 dm, - * mlib_s32 dn, - * mlib_s32 cmask, - * mlib_edge edge) - * - * ARGUMENTS - * dst Pointer to destination image. - * src Pointer to source image. - * m Kernel width (m must be not less than 1). - * n Kernel height (n must be not less than 1). - * dm, dn Position of key element in convolution kernel. - * kernel Pointer to convolution kernel. - * cmask Channel mask to indicate the channels to be convolved. - * Each bit of which represents a channel in the image. The - * channels corresponded to 1 bits are those to be processed. - * edge Type of edge condition. - * - * DESCRIPTION - * 2-D convolution, MxN kernel. - * - * The center of the source image is mapped to the center of the - * destination image. - * The unselected channels are not overwritten. If both src and dst have - * just one channel, cmask is ignored. - * - * The edge condition can be one of the following: - * MLIB_EDGE_DST_NO_WRITE (default) - * MLIB_EDGE_DST_FILL_ZERO - * MLIB_EDGE_DST_COPY_SRC - * MLIB_EDGE_SRC_EXTEND - * - * RESTRICTION - * The src and the dst must be the same type and have same number - * of channels (1, 2, 3, or 4). - * m >= 1, n >= 1, - * 0 <= dm < m, 0 <= dn < n. - */ - -#include "mlib_image.h" -#include "mlib_ImageCheck.h" -#include "mlib_SysMath.h" -#include "mlib_ImageConv.h" -#include "safe_math.h" - -/***************************************************************/ -mlib_status mlib_ImageConvMxN_Fp(mlib_image *dst, - const mlib_image *src, - const mlib_d64 *kernel, - mlib_s32 m, - mlib_s32 n, - mlib_s32 dm, - mlib_s32 dn, - mlib_s32 cmask, - mlib_edge edge) -{ - mlib_type type; - - MLIB_IMAGE_CHECK(dst); - type = mlib_ImageGetType(dst); - - if (type != MLIB_FLOAT && type != MLIB_DOUBLE) - return MLIB_FAILURE; - - return mlib_ImageConvMxN_f(dst, src, kernel, m, n, dm, dn, 0, cmask, edge); -} - -/***************************************************************/ diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_D64nw.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_D64nw.c deleted file mode 100644 index 389c1b52c1eb..000000000000 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_D64nw.c +++ /dev/null @@ -1,582 +0,0 @@ -/* - * Copyright (c) 2003, 2026, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - - -/* - * FUNCTION - * Internal functions for mlib_ImageConv* on D64/F32 type and - * MLIB_EDGE_DST_NO_WRITE mask - * - */ - -#include "mlib_image.h" -#include "mlib_ImageConv.h" - -/***************************************************************/ -/* - This define switches between functions of MLIB_DOUBLE and MLIB_FLOAT types: - Files mlib_ImageConv_D64nw.c and mlib_ImageConv_F32nw.c -*/ - -#define TYPE_DOUBLE - -/***************************************************************/ -#ifdef TYPE_DOUBLE - -#define CONV_FUNC(KERN) mlib_conv##KERN##nw_d64 - -#define DTYPE mlib_d64 - -#else - -#define CONV_FUNC(KERN) mlib_conv##KERN##nw_f32 - -#define DTYPE mlib_f32 - -#endif /* TYPE_DOUBLE */ - -/***************************************************************/ -#define GET_SRC_DST_PARAMETERS(type) \ - mlib_s32 hgt = mlib_ImageGetHeight(src); \ - mlib_s32 wid = mlib_ImageGetWidth(src); \ - mlib_s32 sll = mlib_ImageGetStride(src) / sizeof(type); \ - mlib_s32 dll = mlib_ImageGetStride(dst) / sizeof(type); \ - type* adr_src = mlib_ImageGetData(src); \ - type* adr_dst = mlib_ImageGetData(dst); \ - mlib_s32 chan1 = mlib_ImageGetChannels(src) - -/***************************************************************/ -#define DEF_VARS(type) \ - GET_SRC_DST_PARAMETERS(type); \ - type *sl; \ - type *dl, *dp = NULL; \ - mlib_s32 i = 0, j, c - -/***************************************************************/ -#define BUFF_SIZE 1600 - -#define CACHE_SIZE (64*1024) - -static mlib_status mlib_ImageConv1xN(mlib_image *dst, - const mlib_image *src, - const DTYPE *k, - mlib_s32 n, - mlib_s32 dn, - mlib_s32 cmask) -{ - DTYPE buff[BUFF_SIZE], *pbuff = buff; - const DTYPE *pk; - DTYPE k0, k1, k2, k3; - DTYPE p0, p1, p2, p3, p4; - DTYPE *sp, *sl_c, *dl_c, *sl0; - DEF_VARS(DTYPE); - mlib_s32 off, kh; - mlib_s32 l, hsize, max_hsize; - - hgt -= (n - 1); - adr_dst += dn*dll; - - max_hsize = (CACHE_SIZE/sizeof(DTYPE))/sll; - - if (!max_hsize) max_hsize = 1; - - if (max_hsize > BUFF_SIZE) { - pbuff = mlib_malloc(sizeof(DTYPE)*max_hsize); - } - - sl_c = adr_src; - dl_c = adr_dst; - - for (l = 0; l < hgt; l += hsize) { - hsize = hgt - l; - - if (hsize > max_hsize) hsize = max_hsize; - - for (c = 0; c < chan1; c++) { - if (!(cmask & (1 << (chan1 - 1 - c)))) continue; - - sl = sl_c + c; - dl = dl_c + c; - - for (j = 0; j < hsize; j++) pbuff[j] = 0.0; - - for (i = 0; i < wid; i++) { - sl0 = sl; - - for (off = 0; off < (n - 4); off += 4) { - pk = k + off; - sp = sl0; - - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - p2 = sp[0]; p3 = sp[sll]; p4 = sp[2*sll]; - sp += 3*sll; - - for (j = 0; j < hsize; j += 2) { - p0 = p2; p1 = p3; p2 = p4; - p3 = sp[0]; - p4 = sp[sll]; - - pbuff[j ] += p0*k0 + p1*k1 + p2*k2 + p3*k3; - pbuff[j + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3; - - sp += 2*sll; - } - - sl0 += 4*sll; - } - - pk = k + off; - sp = sl0; - - dp = dl; - kh = n - off; - - if (kh == 4) { - - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - p2 = sp[0]; p3 = sp[sll]; p4 = sp[2*sll]; - - sp += 3*sll; - - for (j = 0; j <= (hsize - 2); j += 2) { - p0 = p2; p1 = p3; p2 = p4; - p3 = sp[0]; - p4 = sp[sll]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + p3*k3 + pbuff[j]; - dp[dll] = p1*k0 + p2*k1 + p3*k2 + p4*k3 + pbuff[j + 1]; - - pbuff[j] = 0; - pbuff[j + 1] = 0; - - sp += 2*sll; - dp += 2*dll; - } - - if (j < hsize) { - p0 = p2; p1 = p3; p2 = p4; - p3 = sp[0]; - - dp[0] = p0*k0 + p1*k1 + p2*k2 + p3*k3 + pbuff[j]; - - pbuff[j] = 0; - } - - } else if (kh == 3) { - - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; - p2 = sp[0]; p3 = sp[sll]; - - sp += 2*sll; - - for (j = 0; j <= (hsize - 2); j += 2) { - p0 = p2; p1 = p3; - p2 = sp[0]; - p3 = sp[sll]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + pbuff[j]; - dp[dll] = p1*k0 + p2*k1 + p3*k2 + pbuff[j + 1]; - - pbuff[j] = 0; - pbuff[j + 1] = 0; - - sp += 2*sll; - dp += 2*dll; - } - - if (j < hsize) { - p0 = p2; p1 = p3; - p2 = sp[0]; - - dp[0] = p0*k0 + p1*k1 + p2*k2 + pbuff[j]; - - pbuff[j] = 0; - } - - } else if (kh == 2) { - - k0 = pk[0]; k1 = pk[1]; - p2 = sp[0]; - - sp += sll; - - for (j = 0; j <= (hsize - 2); j += 2) { - p0 = p2; - p1 = sp[0]; - p2 = sp[sll]; - - dp[0 ] = p0*k0 + p1*k1 + pbuff[j]; - dp[dll] = p1*k0 + p2*k1 + pbuff[j + 1]; - - pbuff[j] = 0; - pbuff[j + 1] = 0; - - sp += 2*sll; - dp += 2*dll; - } - - if (j < hsize) { - p0 = p2; - p1 = sp[0]; - - dp[0] = p0*k0 + p1*k1 + pbuff[j]; - - pbuff[j] = 0; - } - - } else /* if (kh == 1) */ { - - k0 = pk[0]; - - for (j = 0; j < hsize; j++) { - p0 = sp[0]; - - dp[0] = p0*k0 + pbuff[j]; - - pbuff[j] = 0; - - sp += sll; - dp += dll; - } - } - - sl += chan1; - dl += chan1; - } - } - - sl_c += max_hsize*sll; - dl_c += max_hsize*dll; - } - - if (pbuff != buff) mlib_free(pbuff); - - return MLIB_SUCCESS; -} - -/***************************************************************/ -#define MAX_KER 7 -#define MAX_NM 81 - -mlib_status CONV_FUNC(MxN)(mlib_image *dst, - const mlib_image *src, - const mlib_d64 *ker, - mlib_s32 m, - mlib_s32 n, - mlib_s32 dm, - mlib_s32 dn, - mlib_s32 cmask) -{ - DTYPE k0, k1, k2, k3, k4, k5, k6, *sp; - DTYPE p0, p1, p2, p3, p4, p5, p6, p7; - mlib_s32 l, off, kw; - DEF_VARS(DTYPE); - mlib_s32 chan2 = chan1 + chan1; - mlib_s32 chan3 = chan1 + chan2; - -#ifdef TYPE_DOUBLE - const mlib_d64 *k = ker; -#else - mlib_f32 k_arr[MAX_NM], *k = k_arr; - - if (n*m > MAX_NM) { - k = mlib_malloc(n*m*sizeof(mlib_f32)); - - if (k == NULL) return MLIB_FAILURE; - } - - for (i = 0; i < n*m; i++) k[i] = (mlib_f32)ker[i]; -#endif /* TYPE_DOUBLE */ - - if (m == 1) return mlib_ImageConv1xN(dst, src, k, n, dn, cmask); - - wid -= (m - 1); - hgt -= (n - 1); - adr_dst += dn*dll + dm*chan1; - - for (c = 0; c < chan1; c++) { - if (!(cmask & (1 << (chan1 - 1 - c)))) continue; - - sl = adr_src + c; - dl = adr_dst + c; - - for (j = 0; j < hgt; j++) { - const DTYPE *pk = k; - - for (l = 0; l < n; l++) { - DTYPE *sp0 = sl + l*sll; - - for (off = 0; off < m; off += kw, pk += kw, sp0 += chan1) { - kw = m - off; - - if (kw > 2*MAX_KER) kw = MAX_KER; else - if (kw > MAX_KER) kw = kw/2; - - dp = dl; - - if (kw == 7) { - - p2 = sp0[0]; p3 = sp0[chan1]; p4 = sp0[chan2]; - sp0 += chan3; - p5 = sp0[0]; p6 = sp0[chan1]; p7 = sp0[chan2]; - sp = sp0 += chan3; - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - k4 = pk[4]; k5 = pk[5]; k6 = pk[6]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; - - p5 = sp[- chan1]; p6 = sp[0]; p7 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6; - dp[chan1] = p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; - - p5 = sp[- chan1]; p6 = sp[0]; p7 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6; - dp[chan1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6; - - sp += chan2; - dp += chan2; - } - } - - } else if (kw == 6) { - - p2 = sp0[0]; p3 = sp0[chan1]; p4 = sp0[chan2]; - sp0 += chan3; - p5 = sp0[0]; p6 = sp0[chan1]; - sp = sp0 += chan2; - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - k4 = pk[4]; k5 = pk[5]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; - - p5 = sp[0]; p6 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5; - dp[chan1] = p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; - - p5 = sp[0]; p6 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5; - dp[chan1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5; - - sp += chan2; - dp += chan2; - } - } - - } else if (kw == 5) { - - p2 = sp0[0]; p3 = sp0[chan1]; p4 = sp0[chan2]; - sp0 += chan3; - p5 = sp0[0]; - sp = sp0 += chan1; - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - k4 = pk[4]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; - - p4 = sp[0]; p5 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4; - dp[chan1] = p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; - - p4 = sp[0]; p5 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4; - dp[chan1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4; - - sp += chan2; - dp += chan2; - } - } - - } else if (kw == 4) { - - p2 = sp0[0]; p3 = sp0[chan1]; p4 = sp0[chan2]; - sp0 += chan3; - sp = sp0; - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; - - p3 = sp[0]; p4 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + p3*k3; - dp[chan1] = p1*k0 + p2*k1 + p3*k2 + p4*k3; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; - - p3 = sp[0]; p4 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1 + p2*k2 + p3*k3; - dp[chan1] += p1*k0 + p2*k1 + p3*k2 + p4*k3; - - sp += chan2; - dp += chan2; - } - } - - } else if (kw == 3) { - - p2 = sp0[0]; p3 = sp0[chan1]; - sp0 += chan3; - sp = sp0 -= chan1; - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; - - p2 = sp[0]; p3 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2; - dp[chan1] = p1*k0 + p2*k1 + p3*k2; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; - - p2 = sp[0]; p3 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1 + p2*k2; - dp[chan1] += p1*k0 + p2*k1 + p3*k2; - - sp += chan2; - dp += chan2; - } - } - - } else { /* kw == 2 */ - - p2 = sp0[0]; - sp0 += chan3; - sp = sp0 -= chan2; - k0 = pk[0]; k1 = pk[1]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; - - p1 = sp[0]; p2 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1; - dp[chan1] = p1*k0 + p2*k1; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; - - p1 = sp[0]; p2 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1; - dp[chan1] += p1*k0 + p2*k1; - - sp += chan2; - dp += chan2; - } - } - } - } - } - - /* last pixels */ - - if (wid & 1) { - DTYPE *sp0 = sl + i*chan1, s = 0; - const DTYPE *pk = k; - mlib_s32 x; - - for (l = 0; l < n; l++) { - DTYPE *sp = sp0 + l*sll; - - for (x = 0; x < m; x++) s += sp[x*chan1] * (*pk++); - } - - dp[0] = s; - } - - /* next line */ - sl += sll; - dl += dll; - } - } - -#ifndef TYPE_DOUBLE - - if (k != k_arr) mlib_free(k); -#endif /* TYPE_DOUBLE */ - - return MLIB_SUCCESS; -} - -/***************************************************************/ diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_F32nw.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_F32nw.c deleted file mode 100644 index e6c68de5054a..000000000000 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConv_F32nw.c +++ /dev/null @@ -1,579 +0,0 @@ -/* - * Copyright (c) 2003, 2026, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - - -/* - * FUNCTION - * Internal functions for mlib_ImageConv* on D64/F32 type and - * MLIB_EDGE_DST_NO_WRITE mask - * - */ - -#include "mlib_image.h" -#include "mlib_ImageConv.h" - -/***************************************************************/ -/* - This define switches between functions of MLIB_DOUBLE and MLIB_FLOAT types: - Files mlib_ImageConv_D64nw.c and mlib_ImageConv_F32nw.c -*/ - -/* #define TYPE_DOUBLE */ - -/***************************************************************/ -#ifdef TYPE_DOUBLE - -#define CONV_FUNC(KERN) mlib_conv##KERN##nw_d64 - -#define DTYPE mlib_d64 - -#else - -#define CONV_FUNC(KERN) mlib_conv##KERN##nw_f32 - -#define DTYPE mlib_f32 - -#endif /* TYPE_DOUBLE */ - -/***************************************************************/ -#define GET_SRC_DST_PARAMETERS(type) \ - mlib_s32 hgt = mlib_ImageGetHeight(src); \ - mlib_s32 wid = mlib_ImageGetWidth(src); \ - mlib_s32 sll = mlib_ImageGetStride(src) / sizeof(type); \ - mlib_s32 dll = mlib_ImageGetStride(dst) / sizeof(type); \ - type* adr_src = mlib_ImageGetData(src); \ - type* adr_dst = mlib_ImageGetData(dst); \ - mlib_s32 chan1 = mlib_ImageGetChannels(src) - -/***************************************************************/ -#define DEF_VARS(type) \ - GET_SRC_DST_PARAMETERS(type); \ - type *sl; \ - type *dl, *dp = NULL; \ - mlib_s32 i, j, c - -/***************************************************************/ -#define BUFF_SIZE 1600 - -#define CACHE_SIZE (64*1024) - -static mlib_status mlib_ImageConv1xN(mlib_image *dst, - const mlib_image *src, - const DTYPE *k, - mlib_s32 n, - mlib_s32 dn, - mlib_s32 cmask) -{ - DTYPE buff[BUFF_SIZE], *pbuff = buff; - const DTYPE *pk; - DTYPE k0, k1, k2, k3; - DTYPE p0, p1, p2, p3, p4; - DTYPE *sp, *sl_c, *dl_c, *sl0; - DEF_VARS(DTYPE); - mlib_s32 off, kh; - mlib_s32 l, hsize, max_hsize; - - hgt -= (n - 1); - adr_dst += dn*dll; - - max_hsize = (CACHE_SIZE/sizeof(DTYPE))/sll; - - if (!max_hsize) max_hsize = 1; - - if (max_hsize > BUFF_SIZE) { - pbuff = mlib_malloc(sizeof(DTYPE)*max_hsize); - } - - sl_c = adr_src; - dl_c = adr_dst; - - for (l = 0; l < hgt; l += hsize) { - hsize = hgt - l; - - if (hsize > max_hsize) hsize = max_hsize; - - for (c = 0; c < chan1; c++) { - if (!(cmask & (1 << (chan1 - 1 - c)))) continue; - - sl = sl_c + c; - dl = dl_c + c; - - for (j = 0; j < hsize; j++) pbuff[j] = 0.0; - - for (i = 0; i < wid; i++) { - sl0 = sl; - - for (off = 0; off < (n - 4); off += 4) { - pk = k + off; - sp = sl0; - - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - p2 = sp[0]; p3 = sp[sll]; p4 = sp[2*sll]; - sp += 3*sll; - - for (j = 0; j < hsize; j += 2) { - p0 = p2; p1 = p3; p2 = p4; - p3 = sp[0]; - p4 = sp[sll]; - - pbuff[j ] += p0*k0 + p1*k1 + p2*k2 + p3*k3; - pbuff[j + 1] += p1*k0 + p2*k1 + p3*k2 + p4*k3; - - sp += 2*sll; - } - - sl0 += 4*sll; - } - - pk = k + off; - sp = sl0; - - dp = dl; - kh = n - off; - - if (kh == 4) { - - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - p2 = sp[0]; p3 = sp[sll]; p4 = sp[2*sll]; - - sp += 3*sll; - - for (j = 0; j <= (hsize - 2); j += 2) { - p0 = p2; p1 = p3; p2 = p4; - p3 = sp[0]; - p4 = sp[sll]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + p3*k3 + pbuff[j]; - dp[dll] = p1*k0 + p2*k1 + p3*k2 + p4*k3 + pbuff[j + 1]; - - pbuff[j] = 0; - pbuff[j + 1] = 0; - - sp += 2*sll; - dp += 2*dll; - } - - if (j < hsize) { - p0 = p2; p1 = p3; p2 = p4; - p3 = sp[0]; - - dp[0] = p0*k0 + p1*k1 + p2*k2 + p3*k3 + pbuff[j]; - - pbuff[j] = 0; - } - - } else if (kh == 3) { - - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; - p2 = sp[0]; p3 = sp[sll]; - - sp += 2*sll; - - for (j = 0; j <= (hsize - 2); j += 2) { - p0 = p2; p1 = p3; - p2 = sp[0]; - p3 = sp[sll]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + pbuff[j]; - dp[dll] = p1*k0 + p2*k1 + p3*k2 + pbuff[j + 1]; - - pbuff[j] = 0; - pbuff[j + 1] = 0; - - sp += 2*sll; - dp += 2*dll; - } - - if (j < hsize) { - p0 = p2; p1 = p3; - p2 = sp[0]; - - dp[0] = p0*k0 + p1*k1 + p2*k2 + pbuff[j]; - - pbuff[j] = 0; - } - - } else if (kh == 2) { - - k0 = pk[0]; k1 = pk[1]; - p2 = sp[0]; - - sp += sll; - - for (j = 0; j <= (hsize - 2); j += 2) { - p0 = p2; - p1 = sp[0]; - p2 = sp[sll]; - - dp[0 ] = p0*k0 + p1*k1 + pbuff[j]; - dp[dll] = p1*k0 + p2*k1 + pbuff[j + 1]; - - pbuff[j] = 0; - pbuff[j + 1] = 0; - - sp += 2*sll; - dp += 2*dll; - } - - if (j < hsize) { - p0 = p2; - p1 = sp[0]; - - dp[0] = p0*k0 + p1*k1 + pbuff[j]; - - pbuff[j] = 0; - } - - } else /* if (kh == 1) */ { - - k0 = pk[0]; - - for (j = 0; j < hsize; j++) { - p0 = sp[0]; - - dp[0] = p0*k0 + pbuff[j]; - - pbuff[j] = 0; - - sp += sll; - dp += dll; - } - } - - sl += chan1; - dl += chan1; - } - } - - sl_c += max_hsize*sll; - dl_c += max_hsize*dll; - } - - if (pbuff != buff) mlib_free(pbuff); - - return MLIB_SUCCESS; -} - -/***************************************************************/ -#define MAX_KER 7 -#define MAX_NM 81 - -mlib_status CONV_FUNC(MxN)(mlib_image *dst, - const mlib_image *src, - const mlib_d64 *ker, - mlib_s32 m, - mlib_s32 n, - mlib_s32 dm, - mlib_s32 dn, - mlib_s32 cmask) -{ - DTYPE k0, k1, k2, k3, k4, k5, k6, *sp; - DTYPE p0, p1, p2, p3, p4, p5, p6, p7; - mlib_s32 l, off, kw; - DEF_VARS(DTYPE); - mlib_s32 chan2 = chan1 + chan1; - mlib_s32 chan3 = chan1 + chan2; - -#ifdef TYPE_DOUBLE - const mlib_d64 *k = ker; -#else - mlib_f32 k_arr[MAX_NM], *k = k_arr; - - if (n*m > MAX_NM) { - k = mlib_malloc(n*m*sizeof(mlib_f32)); - - if (k == NULL) return MLIB_FAILURE; - } - - for (i = 0; i < n*m; i++) k[i] = (mlib_f32)ker[i]; -#endif /* TYPE_DOUBLE */ - - if (m == 1) return mlib_ImageConv1xN(dst, src, k, n, dn, cmask); - - wid -= (m - 1); - hgt -= (n - 1); - adr_dst += dn*dll + dm*chan1; - - for (c = 0; c < chan1; c++) { - if (!(cmask & (1 << (chan1 - 1 - c)))) continue; - - sl = adr_src + c; - dl = adr_dst + c; - - for (j = 0; j < hgt; j++) { - const DTYPE *pk = k; - - for (l = 0; l < n; l++) { - DTYPE *sp0 = sl + l*sll; - - for (off = 0; off < m; off += kw, pk += kw, sp0 += chan1) { - kw = m - off; - - if (kw > 2*MAX_KER) kw = MAX_KER; else - if (kw > MAX_KER) kw = kw/2; - - dp = dl; - - if (kw == 7) { - p2 = sp0[0]; p3 = sp0[chan1]; p4 = sp0[chan2]; - sp0 += chan3; - p5 = sp0[0]; p6 = sp0[chan1]; p7 = sp0[chan2]; - sp = sp0 += chan3; - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - k4 = pk[4]; k5 = pk[5]; k6 = pk[6]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; - - p5 = sp[- chan1]; p6 = sp[0]; p7 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6; - dp[chan1] = p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; - - p5 = sp[- chan1]; p6 = sp[0]; p7 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5 + p6*k6; - dp[chan1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5 + p7*k6; - - sp += chan2; - dp += chan2; - } - } - - } else if (kw == 6) { - p2 = sp0[0]; p3 = sp0[chan1]; p4 = sp0[chan2]; - sp0 += chan3; - p5 = sp0[0]; p6 = sp0[chan1]; - sp = sp0 += chan2; - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - k4 = pk[4]; k5 = pk[5]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; - - p5 = sp[0]; p6 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5; - dp[chan1] = p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; p4 = p6; - - p5 = sp[0]; p6 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4 + p5*k5; - dp[chan1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4 + p6*k5; - - sp += chan2; - dp += chan2; - } - } - - } else if (kw == 5) { - p2 = sp0[0]; p3 = sp0[chan1]; p4 = sp0[chan2]; - sp0 += chan3; - p5 = sp0[0]; - sp = sp0 += chan1; - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - k4 = pk[4]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; - - p4 = sp[0]; p5 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4; - dp[chan1] = p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; p3 = p5; - - p4 = sp[0]; p5 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1 + p2*k2 + p3*k3 + p4*k4; - dp[chan1] += p1*k0 + p2*k1 + p3*k2 + p4*k3 + p5*k4; - - sp += chan2; - dp += chan2; - } - } - - } else if (kw == 4) { - - p2 = sp0[0]; p3 = sp0[chan1]; p4 = sp0[chan2]; - sp0 += chan3; - sp = sp0; - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; k3 = pk[3]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; - - p3 = sp[0]; p4 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2 + p3*k3; - dp[chan1] = p1*k0 + p2*k1 + p3*k2 + p4*k3; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; p2 = p4; - - p3 = sp[0]; p4 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1 + p2*k2 + p3*k3; - dp[chan1] += p1*k0 + p2*k1 + p3*k2 + p4*k3; - - sp += chan2; - dp += chan2; - } - } - - } else if (kw == 3) { - - p2 = sp0[0]; p3 = sp0[chan1]; - sp0 += chan3; - sp = sp0 -= chan1; - k0 = pk[0]; k1 = pk[1]; k2 = pk[2]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; - - p2 = sp[0]; p3 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1 + p2*k2; - dp[chan1] = p1*k0 + p2*k1 + p3*k2; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; p1 = p3; - - p2 = sp[0]; p3 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1 + p2*k2; - dp[chan1] += p1*k0 + p2*k1 + p3*k2; - - sp += chan2; - dp += chan2; - } - } - - } else { /* kw == 2 */ - - p2 = sp0[0]; - sp0 += chan3; - sp = sp0 -= chan2; - k0 = pk[0]; k1 = pk[1]; - - if (pk == k) { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; - - p1 = sp[0]; p2 = sp[chan1]; - - dp[0 ] = p0*k0 + p1*k1; - dp[chan1] = p1*k0 + p2*k1; - - sp += chan2; - dp += chan2; - } - - } else { - for (i = 0; i <= (wid - 2); i += 2) { - p0 = p2; - - p1 = sp[0]; p2 = sp[chan1]; - - dp[0 ] += p0*k0 + p1*k1; - dp[chan1] += p1*k0 + p2*k1; - - sp += chan2; - dp += chan2; - } - } - } - } - } - - /* last pixels */ - - if (wid & 1) { - DTYPE *sp0 = sl + i*chan1, s = 0; - const DTYPE *pk = k; - mlib_s32 x; - - for (l = 0; l < n; l++) { - DTYPE *sp = sp0 + l*sll; - - for (x = 0; x < m; x++) s += sp[x*chan1] * (*pk++); - } - - dp[0] = s; - } - - /* next line */ - sl += sll; - dl += dll; - } - } - -#ifndef TYPE_DOUBLE - - if (k != k_arr) mlib_free(k); -#endif /* TYPE_DOUBLE */ - - return MLIB_SUCCESS; -} - -/***************************************************************/ diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageDivTables.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageDivTables.c deleted file mode 100644 index 5a12ec39af82..000000000000 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageDivTables.c +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Copyright (c) 1998, 2003, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - - -/* - * DESCRIPTION: - * - * mlib_u16 mlib_div6_tab[x] = 0xff00/6/x; - * mlib_u16 mlib_div1_tab[x] = 0xff00/x; - * mlib_d64 mlib_U82D64[x] = (mlib_d64)x; - * mlib_f32 mlib_U82F32[x] = (mlib_f32)x; - * mlib_f32 mlib_HSL2RGB_L2[x] = x/255.0 for x<128, and (255-x)/255.0 for x >= 128; - * mlib_f32 mlib_HSL2RGB_F[x] = 1.0 - fabs(fraction(x*3/256.) * 4.0f - 2.0) - * - * REFERENCING: - * mlib_div* tables are used to exclude dividing in functions - * mlib_ImageColorRGB2HSV - * mlib_ImageColorRGB2HSL - * mlib_ImageDivAlpha - * - * table mlib_U82D64 is used to exclude conversion unsigned - * byte to double in functions - * mlib_ImageColorConvert... - * mlib_ImageDataTypeConvert - * mlib_ImageAffine - * mlib_ImageAffineTable - * mlib_ImageZoomTranslate - * mlib_ImageZoomTranslateTable - * mlib_ImageGridWarp - * mlib_ImagePolynomialWarp - * mlib_ImageCrossCorrel - * mlib_ImageMoment2 - * mlib_ImageStdDev - * mlib_ImageFourierTransform - * - * table mlib_U82F32 is used to exclude conversion unsigned - * byte to float in functions - * mlib_ImageBlend - * mlib_ImageDivShift - * mlib_ImageMulAlpha - * mlib_ImageMulAlpha_Inp - * mlib_ImageMulShift - * mlib_ImageBlend_BDST_BSRC - * mlib_ImageColorHSL2RGB - * mlib_ImageColorHSV2RGB - * mlib_ImageDataTypeConvert - * mlib_ImageAffine - * mlib_ImageAffineTable - * mlib_ImageZoomTranslate - * mlib_ImageZoomTranslateTable - * mlib_ImageConvMxN - * mlib_ImageSobel - * mlib_ImageGradient3x3 - * mlib_ImageGradientMxN - * - * tables mlib_HSL2RGB_* are used to exclude conversion unsigned - * byte to float in functions with some computations - * mlib_ImageColorHSL2RGB - */ - -#include "mlib_image.h" -#define __DIV_TABLE_DEFINED -#include "mlib_ImageDivTables.h" - -/***************************************************************/ -/* *INDENT-OFF* */ - -const mlib_u16 mlib_div6_tab[] = { - 32767, 10880, 5440, 3627, 2720, 2176, 1813, 1554, - 1360, 1209, 1088, 989, 907, 837, 777, 725, - 680, 640, 604, 573, 544, 518, 495, 473, - 453, 435, 418, 403, 389, 375, 363, 351, - 340, 330, 320, 311, 302, 294, 286, 279, - 272, 265, 259, 253, 247, 242, 237, 231, - 227, 222, 218, 213, 209, 205, 201, 198, - 194, 191, 188, 184, 181, 178, 175, 173, - 170, 167, 165, 162, 160, 158, 155, 153, - 151, 149, 147, 145, 143, 141, 139, 138, - 136, 134, 133, 131, 130, 128, 127, 125, - 124, 122, 121, 120, 118, 117, 116, 115, - 113, 112, 111, 110, 109, 108, 107, 106, - 105, 104, 103, 102, 101, 100, 99, 98, - 97, 96, 95, 95, 94, 93, 92, 91, - 91, 90, 89, 88, 88, 87, 86, 86, - 85, 84, 84, 83, 82, 82, 81, 81, - 80, 79, 79, 78, 78, 77, 77, 76, - 76, 75, 75, 74, 74, 73, 73, 72, - 72, 71, 71, 70, 70, 69, 69, 68, - 68, 68, 67, 67, 66, 66, 66, 65, - 65, 64, 64, 64, 63, 63, 63, 62, - 62, 61, 61, 61, 60, 60, 60, 59, - 59, 59, 58, 58, 58, 58, 57, 57, - 57, 56, 56, 56, 56, 55, 55, 55, - 54, 54, 54, 54, 53, 53, 53, 53, - 52, 52, 52, 52, 51, 51, 51, 51, - 50, 50, 50, 50, 49, 49, 49, 49, - 49, 48, 48, 48, 48, 48, 47, 47, - 47, 47, 46, 46, 46, 46, 46, 46, - 45, 45, 45, 45, 45, 44, 44, 44, - 44, 44, 44, 43, 43, 43, 43, 43 -}; - -/***************************************************************/ - -const mlib_u16 mlib_div1_tab[] = { - 65280, 65280, 32640, 21760, 16320, 13056, 10880, 9326, - 8160, 7253, 6528, 5935, 5440, 5022, 4663, 4352, - 4080, 3840, 3627, 3436, 3264, 3109, 2967, 2838, - 2720, 2611, 2511, 2418, 2331, 2251, 2176, 2106, - 2040, 1978, 1920, 1865, 1813, 1764, 1718, 1674, - 1632, 1592, 1554, 1518, 1484, 1451, 1419, 1389, - 1360, 1332, 1306, 1280, 1255, 1232, 1209, 1187, - 1166, 1145, 1126, 1106, 1088, 1070, 1053, 1036, - 1020, 1004, 989, 974, 960, 946, 933, 919, - 907, 894, 882, 870, 859, 848, 837, 826, - 816, 806, 796, 787, 777, 768, 759, 750, - 742, 733, 725, 717, 710, 702, 694, 687, - 680, 673, 666, 659, 653, 646, 640, 634, - 628, 622, 616, 610, 604, 599, 593, 588, - 583, 578, 573, 568, 563, 558, 553, 549, - 544, 540, 535, 531, 526, 522, 518, 514, - 510, 506, 502, 498, 495, 491, 487, 484, - 480, 476, 473, 470, 466, 463, 460, 457, - 453, 450, 447, 444, 441, 438, 435, 432, - 429, 427, 424, 421, 418, 416, 413, 411, - 408, 405, 403, 400, 398, 396, 393, 391, - 389, 386, 384, 382, 380, 377, 375, 373, - 371, 369, 367, 365, 363, 361, 359, 357, - 355, 353, 351, 349, 347, 345, 344, 342, - 340, 338, 336, 335, 333, 331, 330, 328, - 326, 325, 323, 322, 320, 318, 317, 315, - 314, 312, 311, 309, 308, 306, 305, 304, - 302, 301, 299, 298, 297, 295, 294, 293, - 291, 290, 289, 288, 286, 285, 284, 283, - 281, 280, 279, 278, 277, 275, 274, 273, - 272, 271, 270, 269, 268, 266, 265, 264, - 263, 262, 261, 260, 259, 258, 257, 256 -}; - -/***************************************************************/ - -const mlib_f32 mlib_HSL2RGB_L2[] = { - 0.000000f, 0.003922f, 0.007843f, 0.011765f, 0.015686f, 0.019608f, 0.023529f, 0.027451f, - 0.031373f, 0.035294f, 0.039216f, 0.043137f, 0.047059f, 0.050980f, 0.054902f, 0.058824f, - 0.062745f, 0.066667f, 0.070588f, 0.074510f, 0.078431f, 0.082353f, 0.086275f, 0.090196f, - 0.094118f, 0.098039f, 0.101961f, 0.105882f, 0.109804f, 0.113725f, 0.117647f, 0.121569f, - 0.125490f, 0.129412f, 0.133333f, 0.137255f, 0.141176f, 0.145098f, 0.149020f, 0.152941f, - 0.156863f, 0.160784f, 0.164706f, 0.168627f, 0.172549f, 0.176471f, 0.180392f, 0.184314f, - 0.188235f, 0.192157f, 0.196078f, 0.200000f, 0.203922f, 0.207843f, 0.211765f, 0.215686f, - 0.219608f, 0.223529f, 0.227451f, 0.231373f, 0.235294f, 0.239216f, 0.243137f, 0.247059f, - 0.250980f, 0.254902f, 0.258824f, 0.262745f, 0.266667f, 0.270588f, 0.274510f, 0.278431f, - 0.282353f, 0.286275f, 0.290196f, 0.294118f, 0.298039f, 0.301961f, 0.305882f, 0.309804f, - 0.313725f, 0.317647f, 0.321569f, 0.325490f, 0.329412f, 0.333333f, 0.337255f, 0.341176f, - 0.345098f, 0.349020f, 0.352941f, 0.356863f, 0.360784f, 0.364706f, 0.368627f, 0.372549f, - 0.376471f, 0.380392f, 0.384314f, 0.388235f, 0.392157f, 0.396078f, 0.400000f, 0.403922f, - 0.407843f, 0.411765f, 0.415686f, 0.419608f, 0.423529f, 0.427451f, 0.431373f, 0.435294f, - 0.439216f, 0.443137f, 0.447059f, 0.450980f, 0.454902f, 0.458824f, 0.462745f, 0.466667f, - 0.470588f, 0.474510f, 0.478431f, 0.482353f, 0.486275f, 0.490196f, 0.494118f, 0.498039f, - 0.498039f, 0.494118f, 0.490196f, 0.486275f, 0.482353f, 0.478431f, 0.474510f, 0.470588f, - 0.466667f, 0.462745f, 0.458824f, 0.454902f, 0.450980f, 0.447059f, 0.443137f, 0.439216f, - 0.435294f, 0.431373f, 0.427451f, 0.423529f, 0.419608f, 0.415686f, 0.411765f, 0.407843f, - 0.403922f, 0.400000f, 0.396078f, 0.392157f, 0.388235f, 0.384314f, 0.380392f, 0.376471f, - 0.372549f, 0.368627f, 0.364706f, 0.360784f, 0.356863f, 0.352941f, 0.349020f, 0.345098f, - 0.341176f, 0.337255f, 0.333333f, 0.329412f, 0.325490f, 0.321569f, 0.317647f, 0.313725f, - 0.309804f, 0.305882f, 0.301961f, 0.298039f, 0.294118f, 0.290196f, 0.286275f, 0.282353f, - 0.278431f, 0.274510f, 0.270588f, 0.266667f, 0.262745f, 0.258824f, 0.254902f, 0.250980f, - 0.247059f, 0.243137f, 0.239216f, 0.235294f, 0.231373f, 0.227451f, 0.223529f, 0.219608f, - 0.215686f, 0.211765f, 0.207843f, 0.203922f, 0.200000f, 0.196078f, 0.192157f, 0.188235f, - 0.184314f, 0.180392f, 0.176471f, 0.172549f, 0.168627f, 0.164706f, 0.160784f, 0.156863f, - 0.152941f, 0.149020f, 0.145098f, 0.141176f, 0.137255f, 0.133333f, 0.129412f, 0.125490f, - 0.121569f, 0.117647f, 0.113725f, 0.109804f, 0.105882f, 0.101961f, 0.098039f, 0.094118f, - 0.090196f, 0.086275f, 0.082353f, 0.078431f, 0.074510f, 0.070588f, 0.066667f, 0.062745f, - 0.058824f, 0.054902f, 0.050980f, 0.047059f, 0.043137f, 0.039216f, 0.035294f, 0.031373f, - 0.027451f, 0.023529f, 0.019608f, 0.015686f, 0.011765f, 0.007843f, 0.003922f, 0.000000f -}; - -/***************************************************************/ - -const mlib_f32 mlib_HSL2RGB_F[] = { - -1.000000f, -0.953125f, -0.906250f, -0.859375f, -0.812500f, -0.765625f, -0.718750f, -0.671875f, - -0.625000f, -0.578125f, -0.531250f, -0.484375f, -0.437500f, -0.390625f, -0.343750f, -0.296875f, - -0.250000f, -0.203125f, -0.156250f, -0.109375f, -0.062500f, -0.015625f, 0.031250f, 0.078125f, - 0.125000f, 0.171875f, 0.218750f, 0.265625f, 0.312500f, 0.359375f, 0.406250f, 0.453125f, - 0.500000f, 0.546875f, 0.593750f, 0.640625f, 0.687500f, 0.734375f, 0.781250f, 0.828125f, - 0.875000f, 0.921875f, 0.968750f, 0.984375f, 0.937500f, 0.890625f, 0.843750f, 0.796875f, - 0.750000f, 0.703125f, 0.656250f, 0.609375f, 0.562500f, 0.515625f, 0.468750f, 0.421875f, - 0.375000f, 0.328125f, 0.281250f, 0.234375f, 0.187500f, 0.140625f, 0.093750f, 0.046875f, - 0.000000f, -0.046875f, -0.093750f, -0.140625f, -0.187500f, -0.234375f, -0.281250f, -0.328125f, - -0.375000f, -0.421875f, -0.468750f, -0.515625f, -0.562500f, -0.609375f, -0.656250f, -0.703125f, - -0.750000f, -0.796875f, -0.843750f, -0.890625f, -0.937500f, -0.984375f, -0.968750f, -0.921875f, - -0.875000f, -0.828125f, -0.781250f, -0.734375f, -0.687500f, -0.640625f, -0.593750f, -0.546875f, - -0.500000f, -0.453125f, -0.406250f, -0.359375f, -0.312500f, -0.265625f, -0.218750f, -0.171875f, - -0.125000f, -0.078125f, -0.031250f, 0.015625f, 0.062500f, 0.109375f, 0.156250f, 0.203125f, - 0.250000f, 0.296875f, 0.343750f, 0.390625f, 0.437500f, 0.484375f, 0.531250f, 0.578125f, - 0.625000f, 0.671875f, 0.718750f, 0.765625f, 0.812500f, 0.859375f, 0.906250f, 0.953125f, - 1.000000f, 0.953125f, 0.906250f, 0.859375f, 0.812500f, 0.765625f, 0.718750f, 0.671875f, - 0.625000f, 0.578125f, 0.531250f, 0.484375f, 0.437500f, 0.390625f, 0.343750f, 0.296875f, - 0.250000f, 0.203125f, 0.156250f, 0.109375f, 0.062500f, 0.015625f, -0.031250f, -0.078125f, - -0.125000f, -0.171875f, -0.218750f, -0.265625f, -0.312500f, -0.359375f, -0.406250f, -0.453125f, - -0.500000f, -0.546875f, -0.593750f, -0.640625f, -0.687500f, -0.734375f, -0.781250f, -0.828125f, - -0.875000f, -0.921875f, -0.968750f, -0.984375f, -0.937500f, -0.890625f, -0.843750f, -0.796875f, - -0.750000f, -0.703125f, -0.656250f, -0.609375f, -0.562500f, -0.515625f, -0.468750f, -0.421875f, - -0.375000f, -0.328125f, -0.281250f, -0.234375f, -0.187500f, -0.140625f, -0.093750f, -0.046875f, - 0.000000f, 0.046875f, 0.093750f, 0.140625f, 0.187500f, 0.234375f, 0.281250f, 0.328125f, - 0.375000f, 0.421875f, 0.468750f, 0.515625f, 0.562500f, 0.609375f, 0.656250f, 0.703125f, - 0.750000f, 0.796875f, 0.843750f, 0.890625f, 0.937500f, 0.984375f, 0.968750f, 0.921875f, - 0.875000f, 0.828125f, 0.781250f, 0.734375f, 0.687500f, 0.640625f, 0.593750f, 0.546875f, - 0.500000f, 0.453125f, 0.406250f, 0.359375f, 0.312500f, 0.265625f, 0.218750f, 0.171875f, - 0.125000f, 0.078125f, 0.031250f, -0.015625f, -0.062500f, -0.109375f, -0.156250f, -0.203125f, - -0.250000f, -0.296875f, -0.343750f, -0.390625f, -0.437500f, -0.484375f, -0.531250f, -0.578125f, - -0.625000f, -0.671875f, -0.718750f, -0.765625f, -0.812500f, -0.859375f, -0.906250f, -0.953125f -}; - -/***************************************************************/ - -const mlib_f32 mlib_U82F32[] = { - 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, - 8.0f, 9.0f, 10.0f, 11.0f, 12.0f, 13.0f, 14.0f, 15.0f, - 16.0f, 17.0f, 18.0f, 19.0f, 20.0f, 21.0f, 22.0f, 23.0f, - 24.0f, 25.0f, 26.0f, 27.0f, 28.0f, 29.0f, 30.0f, 31.0f, - 32.0f, 33.0f, 34.0f, 35.0f, 36.0f, 37.0f, 38.0f, 39.0f, - 40.0f, 41.0f, 42.0f, 43.0f, 44.0f, 45.0f, 46.0f, 47.0f, - 48.0f, 49.0f, 50.0f, 51.0f, 52.0f, 53.0f, 54.0f, 55.0f, - 56.0f, 57.0f, 58.0f, 59.0f, 60.0f, 61.0f, 62.0f, 63.0f, - 64.0f, 65.0f, 66.0f, 67.0f, 68.0f, 69.0f, 70.0f, 71.0f, - 72.0f, 73.0f, 74.0f, 75.0f, 76.0f, 77.0f, 78.0f, 79.0f, - 80.0f, 81.0f, 82.0f, 83.0f, 84.0f, 85.0f, 86.0f, 87.0f, - 88.0f, 89.0f, 90.0f, 91.0f, 92.0f, 93.0f, 94.0f, 95.0f, - 96.0f, 97.0f, 98.0f, 99.0f, 100.0f, 101.0f, 102.0f, 103.0f, - 104.0f, 105.0f, 106.0f, 107.0f, 108.0f, 109.0f, 110.0f, 111.0f, - 112.0f, 113.0f, 114.0f, 115.0f, 116.0f, 117.0f, 118.0f, 119.0f, - 120.0f, 121.0f, 122.0f, 123.0f, 124.0f, 125.0f, 126.0f, 127.0f, - 128.0f, 129.0f, 130.0f, 131.0f, 132.0f, 133.0f, 134.0f, 135.0f, - 136.0f, 137.0f, 138.0f, 139.0f, 140.0f, 141.0f, 142.0f, 143.0f, - 144.0f, 145.0f, 146.0f, 147.0f, 148.0f, 149.0f, 150.0f, 151.0f, - 152.0f, 153.0f, 154.0f, 155.0f, 156.0f, 157.0f, 158.0f, 159.0f, - 160.0f, 161.0f, 162.0f, 163.0f, 164.0f, 165.0f, 166.0f, 167.0f, - 168.0f, 169.0f, 170.0f, 171.0f, 172.0f, 173.0f, 174.0f, 175.0f, - 176.0f, 177.0f, 178.0f, 179.0f, 180.0f, 181.0f, 182.0f, 183.0f, - 184.0f, 185.0f, 186.0f, 187.0f, 188.0f, 189.0f, 190.0f, 191.0f, - 192.0f, 193.0f, 194.0f, 195.0f, 196.0f, 197.0f, 198.0f, 199.0f, - 200.0f, 201.0f, 202.0f, 203.0f, 204.0f, 205.0f, 206.0f, 207.0f, - 208.0f, 209.0f, 210.0f, 211.0f, 212.0f, 213.0f, 214.0f, 215.0f, - 216.0f, 217.0f, 218.0f, 219.0f, 220.0f, 221.0f, 222.0f, 223.0f, - 224.0f, 225.0f, 226.0f, 227.0f, 228.0f, 229.0f, 230.0f, 231.0f, - 232.0f, 233.0f, 234.0f, 235.0f, 236.0f, 237.0f, 238.0f, 239.0f, - 240.0f, 241.0f, 242.0f, 243.0f, 244.0f, 245.0f, 246.0f, 247.0f, - 248.0f, 249.0f, 250.0f, 251.0f, 252.0f, 253.0f, 254.0f, 255.0f, - 256.0f -}; - -/***************************************************************/ - -const mlib_d64 mlib_U82D64[] = { - 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, - 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, - 16.0, 17.0, 18.0, 19.0, 20.0, 21.0, 22.0, 23.0, - 24.0, 25.0, 26.0, 27.0, 28.0, 29.0, 30.0, 31.0, - 32.0, 33.0, 34.0, 35.0, 36.0, 37.0, 38.0, 39.0, - 40.0, 41.0, 42.0, 43.0, 44.0, 45.0, 46.0, 47.0, - 48.0, 49.0, 50.0, 51.0, 52.0, 53.0, 54.0, 55.0, - 56.0, 57.0, 58.0, 59.0, 60.0, 61.0, 62.0, 63.0, - 64.0, 65.0, 66.0, 67.0, 68.0, 69.0, 70.0, 71.0, - 72.0, 73.0, 74.0, 75.0, 76.0, 77.0, 78.0, 79.0, - 80.0, 81.0, 82.0, 83.0, 84.0, 85.0, 86.0, 87.0, - 88.0, 89.0, 90.0, 91.0, 92.0, 93.0, 94.0, 95.0, - 96.0, 97.0, 98.0, 99.0, 100.0, 101.0, 102.0, 103.0, - 104.0, 105.0, 106.0, 107.0, 108.0, 109.0, 110.0, 111.0, - 112.0, 113.0, 114.0, 115.0, 116.0, 117.0, 118.0, 119.0, - 120.0, 121.0, 122.0, 123.0, 124.0, 125.0, 126.0, 127.0, - 128.0, 129.0, 130.0, 131.0, 132.0, 133.0, 134.0, 135.0, - 136.0, 137.0, 138.0, 139.0, 140.0, 141.0, 142.0, 143.0, - 144.0, 145.0, 146.0, 147.0, 148.0, 149.0, 150.0, 151.0, - 152.0, 153.0, 154.0, 155.0, 156.0, 157.0, 158.0, 159.0, - 160.0, 161.0, 162.0, 163.0, 164.0, 165.0, 166.0, 167.0, - 168.0, 169.0, 170.0, 171.0, 172.0, 173.0, 174.0, 175.0, - 176.0, 177.0, 178.0, 179.0, 180.0, 181.0, 182.0, 183.0, - 184.0, 185.0, 186.0, 187.0, 188.0, 189.0, 190.0, 191.0, - 192.0, 193.0, 194.0, 195.0, 196.0, 197.0, 198.0, 199.0, - 200.0, 201.0, 202.0, 203.0, 204.0, 205.0, 206.0, 207.0, - 208.0, 209.0, 210.0, 211.0, 212.0, 213.0, 214.0, 215.0, - 216.0, 217.0, 218.0, 219.0, 220.0, 221.0, 222.0, 223.0, - 224.0, 225.0, 226.0, 227.0, 228.0, 229.0, 230.0, 231.0, - 232.0, 233.0, 234.0, 235.0, 236.0, 237.0, 238.0, 239.0, - 240.0, 241.0, 242.0, 243.0, 244.0, 245.0, 246.0, 247.0, - 248.0, 249.0, 250.0, 251.0, 252.0, 253.0, 254.0, 255.0, - 256.0 -}; - -/***************************************************************/ - -const mlib_u32 mlib_FlipAndFixRotateTable[] = { - 0x00000000, 0x00000000, 0x00000000, 0x00000080, - 0x00000000, 0x00008000, 0x00000000, 0x00008080, - 0x00000000, 0x00800000, 0x00000000, 0x00800080, - 0x00000000, 0x00808000, 0x00000000, 0x00808080, - 0x00000000, 0x80000000, 0x00000000, 0x80000080, - 0x00000000, 0x80008000, 0x00000000, 0x80008080, - 0x00000000, 0x80800000, 0x00000000, 0x80800080, - 0x00000000, 0x80808000, 0x00000000, 0x80808080, - 0x00000080, 0x00000000, 0x00000080, 0x00000080, - 0x00000080, 0x00008000, 0x00000080, 0x00008080, - 0x00000080, 0x00800000, 0x00000080, 0x00800080, - 0x00000080, 0x00808000, 0x00000080, 0x00808080, - 0x00000080, 0x80000000, 0x00000080, 0x80000080, - 0x00000080, 0x80008000, 0x00000080, 0x80008080, - 0x00000080, 0x80800000, 0x00000080, 0x80800080, - 0x00000080, 0x80808000, 0x00000080, 0x80808080, - 0x00008000, 0x00000000, 0x00008000, 0x00000080, - 0x00008000, 0x00008000, 0x00008000, 0x00008080, - 0x00008000, 0x00800000, 0x00008000, 0x00800080, - 0x00008000, 0x00808000, 0x00008000, 0x00808080, - 0x00008000, 0x80000000, 0x00008000, 0x80000080, - 0x00008000, 0x80008000, 0x00008000, 0x80008080, - 0x00008000, 0x80800000, 0x00008000, 0x80800080, - 0x00008000, 0x80808000, 0x00008000, 0x80808080, - 0x00008080, 0x00000000, 0x00008080, 0x00000080, - 0x00008080, 0x00008000, 0x00008080, 0x00008080, - 0x00008080, 0x00800000, 0x00008080, 0x00800080, - 0x00008080, 0x00808000, 0x00008080, 0x00808080, - 0x00008080, 0x80000000, 0x00008080, 0x80000080, - 0x00008080, 0x80008000, 0x00008080, 0x80008080, - 0x00008080, 0x80800000, 0x00008080, 0x80800080, - 0x00008080, 0x80808000, 0x00008080, 0x80808080, - 0x00800000, 0x00000000, 0x00800000, 0x00000080, - 0x00800000, 0x00008000, 0x00800000, 0x00008080, - 0x00800000, 0x00800000, 0x00800000, 0x00800080, - 0x00800000, 0x00808000, 0x00800000, 0x00808080, - 0x00800000, 0x80000000, 0x00800000, 0x80000080, - 0x00800000, 0x80008000, 0x00800000, 0x80008080, - 0x00800000, 0x80800000, 0x00800000, 0x80800080, - 0x00800000, 0x80808000, 0x00800000, 0x80808080, - 0x00800080, 0x00000000, 0x00800080, 0x00000080, - 0x00800080, 0x00008000, 0x00800080, 0x00008080, - 0x00800080, 0x00800000, 0x00800080, 0x00800080, - 0x00800080, 0x00808000, 0x00800080, 0x00808080, - 0x00800080, 0x80000000, 0x00800080, 0x80000080, - 0x00800080, 0x80008000, 0x00800080, 0x80008080, - 0x00800080, 0x80800000, 0x00800080, 0x80800080, - 0x00800080, 0x80808000, 0x00800080, 0x80808080, - 0x00808000, 0x00000000, 0x00808000, 0x00000080, - 0x00808000, 0x00008000, 0x00808000, 0x00008080, - 0x00808000, 0x00800000, 0x00808000, 0x00800080, - 0x00808000, 0x00808000, 0x00808000, 0x00808080, - 0x00808000, 0x80000000, 0x00808000, 0x80000080, - 0x00808000, 0x80008000, 0x00808000, 0x80008080, - 0x00808000, 0x80800000, 0x00808000, 0x80800080, - 0x00808000, 0x80808000, 0x00808000, 0x80808080, - 0x00808080, 0x00000000, 0x00808080, 0x00000080, - 0x00808080, 0x00008000, 0x00808080, 0x00008080, - 0x00808080, 0x00800000, 0x00808080, 0x00800080, - 0x00808080, 0x00808000, 0x00808080, 0x00808080, - 0x00808080, 0x80000000, 0x00808080, 0x80000080, - 0x00808080, 0x80008000, 0x00808080, 0x80008080, - 0x00808080, 0x80800000, 0x00808080, 0x80800080, - 0x00808080, 0x80808000, 0x00808080, 0x80808080, - 0x80000000, 0x00000000, 0x80000000, 0x00000080, - 0x80000000, 0x00008000, 0x80000000, 0x00008080, - 0x80000000, 0x00800000, 0x80000000, 0x00800080, - 0x80000000, 0x00808000, 0x80000000, 0x00808080, - 0x80000000, 0x80000000, 0x80000000, 0x80000080, - 0x80000000, 0x80008000, 0x80000000, 0x80008080, - 0x80000000, 0x80800000, 0x80000000, 0x80800080, - 0x80000000, 0x80808000, 0x80000000, 0x80808080, - 0x80000080, 0x00000000, 0x80000080, 0x00000080, - 0x80000080, 0x00008000, 0x80000080, 0x00008080, - 0x80000080, 0x00800000, 0x80000080, 0x00800080, - 0x80000080, 0x00808000, 0x80000080, 0x00808080, - 0x80000080, 0x80000000, 0x80000080, 0x80000080, - 0x80000080, 0x80008000, 0x80000080, 0x80008080, - 0x80000080, 0x80800000, 0x80000080, 0x80800080, - 0x80000080, 0x80808000, 0x80000080, 0x80808080, - 0x80008000, 0x00000000, 0x80008000, 0x00000080, - 0x80008000, 0x00008000, 0x80008000, 0x00008080, - 0x80008000, 0x00800000, 0x80008000, 0x00800080, - 0x80008000, 0x00808000, 0x80008000, 0x00808080, - 0x80008000, 0x80000000, 0x80008000, 0x80000080, - 0x80008000, 0x80008000, 0x80008000, 0x80008080, - 0x80008000, 0x80800000, 0x80008000, 0x80800080, - 0x80008000, 0x80808000, 0x80008000, 0x80808080, - 0x80008080, 0x00000000, 0x80008080, 0x00000080, - 0x80008080, 0x00008000, 0x80008080, 0x00008080, - 0x80008080, 0x00800000, 0x80008080, 0x00800080, - 0x80008080, 0x00808000, 0x80008080, 0x00808080, - 0x80008080, 0x80000000, 0x80008080, 0x80000080, - 0x80008080, 0x80008000, 0x80008080, 0x80008080, - 0x80008080, 0x80800000, 0x80008080, 0x80800080, - 0x80008080, 0x80808000, 0x80008080, 0x80808080, - 0x80800000, 0x00000000, 0x80800000, 0x00000080, - 0x80800000, 0x00008000, 0x80800000, 0x00008080, - 0x80800000, 0x00800000, 0x80800000, 0x00800080, - 0x80800000, 0x00808000, 0x80800000, 0x00808080, - 0x80800000, 0x80000000, 0x80800000, 0x80000080, - 0x80800000, 0x80008000, 0x80800000, 0x80008080, - 0x80800000, 0x80800000, 0x80800000, 0x80800080, - 0x80800000, 0x80808000, 0x80800000, 0x80808080, - 0x80800080, 0x00000000, 0x80800080, 0x00000080, - 0x80800080, 0x00008000, 0x80800080, 0x00008080, - 0x80800080, 0x00800000, 0x80800080, 0x00800080, - 0x80800080, 0x00808000, 0x80800080, 0x00808080, - 0x80800080, 0x80000000, 0x80800080, 0x80000080, - 0x80800080, 0x80008000, 0x80800080, 0x80008080, - 0x80800080, 0x80800000, 0x80800080, 0x80800080, - 0x80800080, 0x80808000, 0x80800080, 0x80808080, - 0x80808000, 0x00000000, 0x80808000, 0x00000080, - 0x80808000, 0x00008000, 0x80808000, 0x00008080, - 0x80808000, 0x00800000, 0x80808000, 0x00800080, - 0x80808000, 0x00808000, 0x80808000, 0x00808080, - 0x80808000, 0x80000000, 0x80808000, 0x80000080, - 0x80808000, 0x80008000, 0x80808000, 0x80008080, - 0x80808000, 0x80800000, 0x80808000, 0x80800080, - 0x80808000, 0x80808000, 0x80808000, 0x80808080, - 0x80808080, 0x00000000, 0x80808080, 0x00000080, - 0x80808080, 0x00008000, 0x80808080, 0x00008080, - 0x80808080, 0x00800000, 0x80808080, 0x00800080, - 0x80808080, 0x00808000, 0x80808080, 0x00808080, - 0x80808080, 0x80000000, 0x80808080, 0x80000080, - 0x80808080, 0x80008000, 0x80808080, 0x80008080, - 0x80808080, 0x80800000, 0x80808080, 0x80800080, - 0x80808080, 0x80808000, 0x80808080, 0x80808080, -}; - -/* *INDENT-ON* */ -/***************************************************************/ diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageDivTables.h b/src/java.desktop/share/native/libmlib_image/mlib_ImageDivTables.h deleted file mode 100644 index 831d9cc20533..000000000000 --- a/src/java.desktop/share/native/libmlib_image/mlib_ImageDivTables.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - - -#ifndef __MLIB_IMAGEDIVTABLES_H -#define __MLIB_IMAGEDIVTABLES_H - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifdef __DIV_TABLE_DEFINED - -const mlib_u16 mlib_div6_tab[]; -const mlib_u16 mlib_div1_tab[]; -const mlib_f32 mlib_HSL2RGB_L2[]; -const mlib_f32 mlib_HSL2RGB_F[]; -const mlib_f32 mlib_U82F32[]; -const mlib_d64 mlib_U82D64[]; -const mlib_u32 mlib_FlipAndFixRotateTable[]; - -#else - -extern const mlib_u16 mlib_div6_tab[]; -extern const mlib_u16 mlib_div1_tab[]; -extern const mlib_f32 mlib_HSL2RGB_L2[]; -extern const mlib_f32 mlib_HSL2RGB_F[]; -extern const mlib_f32 mlib_U82F32[]; -extern const mlib_d64 mlib_U82D64[]; -extern const mlib_u32 mlib_FlipAndFixRotateTable[]; - -#endif /* __DIV_TABLE_DEFINED */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* __MLIB_IMAGEDIVTABLES_H */ - -/***************************************************************/ diff --git a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageAffine_BL.c b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageAffine_BL.c index ccb0a564674c..631956ce44a1 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageAffine_BL.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageAffine_BL.c @@ -71,7 +71,7 @@ /***************************************************************/ #define TTYPE mlib_f32 -#define I2F(x) mlib_U82F32[x] +#define I2F(x) ((mlib_f32)(x)) #define ROUND(x) ((x) + 0.5f) #define FUN_NAME(CHAN) mlib_ImageAffine_u8_##CHAN##_bl diff --git a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConvClearEdge.c b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConvClearEdge.c index 08644f9d7dc9..9832f1c6424f 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConvClearEdge.c +++ b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageConvClearEdge.c @@ -164,7 +164,7 @@ mlib_status mlib_ImageConvZeroEdge(mlib_image *dst, mlib_type type = mlib_ImageGetType(dst); if (type == MLIB_FLOAT || type == MLIB_DOUBLE) { - return mlib_ImageConvClearEdge_Fp(dst, dx_l, dx_r, dy_t, dy_b, zero, cmask); + return MLIB_FAILURE; } else { return mlib_ImageConvClearEdge(dst, dx_l, dx_r, dy_t, dy_b, (mlib_s32 *) zero, cmask); diff --git a/src/java.desktop/share/native/libmlib_image/mlib_image_proto.h b/src/java.desktop/share/native/libmlib_image/mlib_image_proto.h index 8155d73e2053..a8ad65e7c4b9 100644 --- a/src/java.desktop/share/native/libmlib_image/mlib_image_proto.h +++ b/src/java.desktop/share/native/libmlib_image/mlib_image_proto.h @@ -2651,20 +2651,6 @@ __mlib_ImageConvMxN(mlib_image *dst, mlib_edge edge); -#if defined ( __MEDIALIB_OLD_NAMES ) -#define __mlib_ImageConvMxN_Fp mlib_ImageConvMxN_Fp -#endif /* ! defined ( __MEDIALIB_OLD_NAMES ) */ -mlib_status __mlib_ImageConvMxN_Fp(mlib_image *dst, - const mlib_image *src, - const mlib_d64 *kernel, - mlib_s32 m, - mlib_s32 n, - mlib_s32 dm, - mlib_s32 dn, - mlib_s32 cmask, - mlib_edge edge); - - #if defined ( __MEDIALIB_OLD_NAMES ) #define __mlib_ImageConvolveMxN mlib_ImageConvolveMxN #endif /* ! defined ( __MEDIALIB_OLD_NAMES ) */ @@ -2678,21 +2664,6 @@ mlib_status __mlib_ImageConvolveMxN(mlib_image *dst, mlib_s32 cmask, mlib_edge edge); - -#if defined ( __MEDIALIB_OLD_NAMES ) -#define __mlib_ImageConvolveMxN_Fp mlib_ImageConvolveMxN_Fp -#endif /* ! defined ( __MEDIALIB_OLD_NAMES ) */ -mlib_status __mlib_ImageConvolveMxN_Fp(mlib_image *dst, - const mlib_image *src, - const mlib_d64 *kernel, - mlib_s32 m, - mlib_s32 n, - mlib_s32 dm, - mlib_s32 dn, - mlib_s32 cmask, - mlib_edge edge); - - #if defined ( __MEDIALIB_OLD_NAMES ) #define __mlib_ImageDilate4 mlib_ImageDilate4 #endif /* ! defined ( __MEDIALIB_OLD_NAMES ) */ diff --git a/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c b/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c index af50fdbb5c08..a5f98588018e 100644 --- a/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c +++ b/src/java.desktop/unix/native/libawt/awt/awt_LoadLibrary.c @@ -33,7 +33,6 @@ #include "gdefs.h" #include -#include #ifdef AIX #define dladdr JVM_dladdr @@ -51,8 +50,6 @@ static void *awtHandle = NULL; -typedef jint JNICALL JNI_OnLoad_type(JavaVM *vm, void *reserved); - /* Initialize the Java VM instance variable when the library is first loaded */ JNIEXPORT JavaVM *jvm; @@ -102,10 +99,7 @@ AWT_OnLoad(JavaVM *vm, void *reserved) char buf[MAXPATHLEN]; int32_t len; char *p, *tk; - JNI_OnLoad_type *JNI_OnLoad_ptr; - struct utsname name; JNIEnv *env = (JNIEnv *)JNU_GetEnv(vm, JNI_VERSION_1_2); - void *v; if (awtHandle != NULL) { /* Avoid several loading attempts */ diff --git a/src/java.desktop/unix/native/libawt/awt/awt_Mlib.c b/src/java.desktop/unix/native/libawt/awt/awt_Mlib.c index c3ecec3380e2..5862ab1f47bd 100644 --- a/src/java.desktop/unix/native/libawt/awt/awt_Mlib.c +++ b/src/java.desktop/unix/native/libawt/awt/awt_Mlib.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, 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 @@ -85,11 +85,7 @@ mlib_status awt_getImagingLib(JNIEnv *env, mlibFnS_t *sMlibFns, */ mlib_status awt_getImagingLib(JNIEnv *env, mlibFnS_t *sMlibFns, mlibSysFnS_t *sMlibSysFns) { - int status; - jstring jstr = NULL; mlibFnS_t *mptr; - void *(*vPtr)(); - int (*intPtr)(); mlib_status (*fPtr)(); int i; void *handle = NULL; @@ -97,7 +93,6 @@ mlib_status awt_getImagingLib(JNIEnv *env, mlibFnS_t *sMlibFns, static int s_timeIt = 0; static int s_verbose = 1; mlib_status ret = MLIB_SUCCESS; - struct utsname name; handle = dlopen(JNI_LIB_NAME("mlib_image"), RTLD_LAZY); diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WDesktopPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WDesktopPeer.java index e5b628dd74bc..06df8223931f 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WDesktopPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WDesktopPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, 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 @@ -105,7 +105,12 @@ public void mail(URI uri) throws IOException { @Override public void browse(URI uri) throws IOException { - this.launchUriInBrowser(uri); + if (isBrowseInsecureAllowed(uri)) { + this.ShellExecute(uri, ACTION_OPEN_VERB); + } else { + // Fall back to opening the URI in browser + this.launchUriInBrowser(uri); + } } private void ShellExecute(File file, String verb) throws IOException { diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/ImmutableExtendedSSLSession.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/ImmutableExtendedSSLSession.java index 2a5f125c0c48..b50e99decd40 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/ImmutableExtendedSSLSession.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/ImmutableExtendedSSLSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 @@ -132,6 +132,10 @@ public String[] getPeerSupportedSignatureAlgorithms() { return delegate.getPeerSupportedSignatureAlgorithms(); } + public String getNamedGroup() { + return delegate.getNamedGroup(); + } + public List getRequestedServerNames() { return delegate.getRequestedServerNames(); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java index 9caa59d5bf7c..be2bb631b84e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Flags.java @@ -180,6 +180,7 @@ public static EnumSet asFlagSet(long flags) { /** Marks a type as a value class */ @Use({FlagTarget.CLASS}) + @CustomToStringValue("value") public static final int VALUE_CLASS = 1<<20; /** A parameter of a lambda function. diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java index c87948fa66dc..fabf3d150187 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Types.java @@ -4184,16 +4184,24 @@ private Type arraySuperType() { // public Type glb(List ts) { + return glb(ts, new HashSet<>()); + } + //where + private Type glb(List ts, Set seenCvars) { Type t1 = ts.head; for (Type t2 : ts.tail) { if (t1.isErroneous()) return t1; - t1 = glb(t1, t2); + t1 = glb(t1, t2, seenCvars); } return t1; } //where public Type glb(Type t, Type s) { + return glb(t, s, new HashSet<>()); + } + //where + private Type glb(Type t, Type s, Set seenCvars) { if (s == null) return t; else if (t.isPrimitive() || s.isPrimitive()) @@ -4204,7 +4212,7 @@ else if (isSubtypeNoCapture(s, t)) return s; List closure = union(closure(t), closure(s)); - return glbFlattened(closure, t); + return glbFlattened(closure, t, seenCvars); } //where /** @@ -4214,8 +4222,10 @@ else if (isSubtypeNoCapture(s, t)) * * @param flatBounds List of type to glb * @param errT Original type to use if the result is an error type + * @param seenCvars capture variables already replaced by their + * lower bound earlier in this glb computation */ - private Type glbFlattened(List flatBounds, Type errT) { + private Type glbFlattened(List flatBounds, Type errT, Set seenCvars) { List bounds = closureMin(flatBounds); if (bounds.isEmpty()) { // length == 0 @@ -4237,12 +4247,18 @@ private Type glbFlattened(List flatBounds, Type errT) { } } if (classCount > 1) { - if (lowers.isEmpty()) { + boolean progress = true; + for (Type cvar : cvars) { + if (!seenCvars.add(cvar)) { + progress = false; + } + } + if (lowers.isEmpty() || !progress) { return createErrorType(errT); } else { // try again with lower bounds included instead of capture variables List newBounds = bounds.diff(cvars).appendList(lowers); - return glb(newBounds); + return glb(newBounds, seenCvars); } } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java index 0697a80a81a4..6d754fb567f7 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ExhaustivenessComputer.java @@ -135,7 +135,7 @@ private ExhaustivenessResult doExhausts(JCExpression selector, List case } } else if (l instanceof JCConstantCaseLabel constantLabel) { if (types.unboxedTypeOrType(selector.type).hasTag(TypeTag.BOOLEAN)) { - Object value = ((JCLiteral) constantLabel.expr).value; + Object value = constantLabel.expr.type.constValue(); booleanLiterals.remove(value); } else { Symbol s = TreeInfo.symbol(constantLabel.expr); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java index 86bdc5ac7b7e..8597b30b11f2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, 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 @@ -720,6 +720,10 @@ VarSymbol addParametersReturnReceiver() { rcvr = new VarSymbol(SYNTHETIC, names.fromString("rec$"), tree.getQualifierExpression().type, owner); rcvr.pos = tree.pos; receiverExpression = attr.makeNullCheck(tree.getQualifierExpression()); + if (receiverExpression.hasTag(Tag.NULLCHK)) { + Type t = types.skipTypeVars(tree.getQualifierExpression().type, false); + receiverExpression.type = t.isCompound() ? erasure(tree.sym.owner.type) : erasure(t); + } break; case UNBOUND: // The receiver is the first parameter, extract it and @@ -962,7 +966,11 @@ public void visitNewClass(JCNewClass tree) { if (tree.def == null) { tree.encl = translate(tree.encl, erasure(tree.encl.type)); } else { - tree.args = tree.args.prepend(attr.makeNullCheck(tree.encl)); + JCExpression expr = attr.makeNullCheck(tree.encl); + if (expr.hasTag(Tag.NULLCHK)) { + expr.type = erasure(tree.encl.type); + } + tree.args = tree.args.prepend(expr); tree.encl = null; } } 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 19daed61aa75..2d17523ed4fe 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 @@ -982,6 +982,9 @@ public JCPattern parsePattern(int pos, JCModifiers mods, JCExpression parsedType mods = mods != null ? mods : optFinal(0); JCExpression e; if (token.kind == UNDERSCORE && parsedType == null) { + if (!allowVar && Feature.UNNAMED_VARIABLES.allowedInSource(source)){ + log.error(DiagnosticFlag.SYNTAX, token.pos, Errors.UseOfUnderscoreNotAllowedNonVariable); + } nextToken(); checkSourceLevel(Feature.UNNAMED_VARIABLES); pattern = toP(F.at(token.pos).AnyPattern()); diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c index 6e39b95e7eca..30d4cb9c7268 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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,6 +29,279 @@ extern void print_debug(const char*,...); +// Directory that contains global debuginfo files. In theory it +// should be possible to change this, but in a Java environment there +// is no obvious place to put a user interface to do it. Maybe this +// could be set with an environment variable. +static const char debug_file_directory[] = "/usr/lib/debug"; + +/* The CRC used in gnu_debuglink, retrieved from + http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files. */ +unsigned int gnu_debuglink_crc32 (unsigned int crc, + unsigned char *buf, size_t len) +{ + static const unsigned int crc32_table[256] = + { + 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, + 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, + 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, + 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, + 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, + 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, + 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, + 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, + 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, + 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, + 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, + 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, + 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, + 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, + 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, + 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, + 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, + 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, + 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, + 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, + 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, + 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, + 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, + 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, + 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, + 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, + 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, + 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, + 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, + 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, + 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, + 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, + 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, + 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, + 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, + 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, + 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, + 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, + 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, + 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, + 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, + 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, + 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, + 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, + 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, + 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, + 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, + 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, + 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, + 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, + 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, + 0x2d02ef8d + }; + unsigned char *end; + + crc = ~crc & 0xffffffff; + for (end = buf + len; buf < end; ++buf) + crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); + return ~crc & 0xffffffff; +} + +/* Open a debuginfo file and check its CRC. If it exists and the CRC + matches return its fd. */ +static int +open_debug_file (const char *pathname, unsigned int crc) +{ + unsigned int file_crc = 0; + unsigned char buffer[8 * 1024]; + + int fd = pathmap_open(pathname); + + if (fd < 0) + return -1; + + lseek(fd, 0, SEEK_SET); + + for (;;) { + int len = read(fd, buffer, sizeof buffer); + if (len <= 0) + break; + file_crc = gnu_debuglink_crc32(file_crc, buffer, len); + } + + if (crc == file_crc) + return fd; + else { + close(fd); + return -1; + } +} + +/* Look for a ".gnu_debuglink" section. If one exists, try to open a + suitable debuginfo file. */ +static int open_debuginfo_from_debug_link(const char *name, + int fd, + ELF_EHDR *ehdr, + struct elf_section *scn_cache) +{ + int debug_fd; + struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr, + scn_cache); + if (debug_link == NULL) + return -1; + char *debug_filename = debug_link->c_data; + int offset = (strlen(debug_filename) + 4) >> 2; + static unsigned int crc; + crc = ((unsigned int*)debug_link->c_data)[offset]; + char *debug_pathname = malloc(strlen(debug_filename) + + strlen(name) + + strlen(".debug/") + + strlen(debug_file_directory) + + 2); + if (debug_pathname == NULL) { + return -1; + } + strcpy(debug_pathname, name); + char *last_slash = strrchr(debug_pathname, '/'); + if (last_slash == NULL) { + free(debug_pathname); + return -1; + } + + /* Look in the same directory as the object. */ + strcpy(last_slash+1, debug_filename); + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + + /* Look in a subdirectory named ".debug". */ + strcpy(last_slash+1, ".debug/"); + strcat(last_slash, debug_filename); + + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + /* Look in /usr/lib/debug + the full pathname. */ + strcpy(debug_pathname, debug_file_directory); + strcat(debug_pathname, name); + last_slash = strrchr(debug_pathname, '/'); + strcpy(last_slash+1, debug_filename); + + debug_fd = open_debug_file(debug_pathname, crc); + if (debug_fd >= 0) { + free(debug_pathname); + return debug_fd; + } + + free(debug_pathname); + return -1; +} + +static char* build_id_to_debug_filename (size_t size, unsigned char* data) { + char *filename, *s; + + filename = malloc(strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 + + 2 * size + (sizeof ".debug" - 1) + 1); + if (filename == NULL) { + return NULL; + } + s = filename + sprintf (filename, "%s/.build-id/", debug_file_directory); + if (size > 0) { + size--; + s += sprintf (s, "%02x", *data++); + } + if (size > 0) { + *s++ = '/'; + } + while (size-- > 0) { + s += sprintf (s, "%02x", *data++); + } + strcpy (s, ".debug"); + + return filename; +} + +static int open_debuginfo_from_build_id(ELF_SHDR* shbuf, ELF_EHDR* ehdr, struct elf_section* scn_cache) { +#ifdef NT_GNU_BUILD_ID + int cnt = 0; + ELF_SHDR* cursct = NULL; + + // First we look for a Build ID + for (cursct = shbuf, cnt = 0; cnt < ehdr->e_shnum; cnt++) { + if (cursct->sh_type == SHT_NOTE) { + Elf64_Nhdr *note = (Elf64_Nhdr *)scn_cache[cnt].c_data; + if (note->n_type == NT_GNU_BUILD_ID) { + unsigned char *bytes = (unsigned char*)(note+1) + note->n_namesz; + char *filename = build_id_to_debug_filename(note->n_descsz, bytes); + if (filename != NULL) { + int fd = pathmap_open(filename); + free(filename); + return fd; + } + } + } + cursct++; + } +#endif + return -1; +} + +int open_debuginfo(const char* filename, int fd) { + // prepare (load ELF sections) + ELF_EHDR ehdr; + if (!read_elf_header(fd, &ehdr)) { + return -1; + } + + ELF_SHDR* shbuf = NULL; + if ((shbuf = read_section_header_table(fd, &ehdr)) == NULL) { + return -1; + } + if (ehdr.e_shnum == 0) { + // calloc() might return the pointer which should not be accessed + // if the size is zero. (implementation-defined) + free(shbuf); + return -1; + } + + struct elf_section *scn_cache = (struct elf_section *)calloc(ehdr.e_shnum, sizeof(struct elf_section)); + if (scn_cache == NULL) { + free(shbuf); + return -1; + } + + bool read_failure = false; + for (int cnt = 0; cnt < ehdr.e_shnum; cnt++) { + scn_cache[cnt].c_shdr = &shbuf[cnt]; + if (shbuf[cnt].sh_type == SHT_NOTE || shbuf[cnt].sh_type == SHT_STRTAB) { + scn_cache[cnt].c_data = read_section_data(fd, &ehdr, &shbuf[cnt]); + if (scn_cache[cnt].c_data == NULL) { + read_failure = true; + break; + } + } + } + + int debug_fd = -1; + if (!read_failure) { + // attempt to open debuginfo + debug_fd = open_debuginfo_from_debug_link(filename, fd, &ehdr, scn_cache); + if (debug_fd == -1) { + // try again with build id. + debug_fd = open_debuginfo_from_build_id(shbuf, &ehdr, scn_cache); + } + } + + // cleanup + for (int cnt = 0; cnt < ehdr.e_shnum; cnt++) { + free(scn_cache[cnt].c_data); + } + free(scn_cache); + free(shbuf); + + return debug_fd; +} + // ELF file parsing helpers. Note that we do *not* use libelf here. int read_elf_header(int fd, ELF_EHDR* ehdr) { if (pread(fd, ehdr, sizeof (ELF_EHDR), 0) != sizeof (ELF_EHDR) || diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h index 59b5039416e8..d82bf794af26 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/salibelf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, 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 @@ -34,6 +34,13 @@ struct elf_section { void *c_data; }; +#ifdef __cplusplus +extern "C" { +#endif + +// open debuginfo +int open_debuginfo(const char* filename, int fd); + // read ELF file header. int read_elf_header(int fd, ELF_EHDR* ehdr); @@ -60,4 +67,9 @@ struct elf_section *find_section_by_name(char *name, int fd, ELF_EHDR *ehdr, struct elf_section *scn_cache); + +#ifdef __cplusplus +} +#endif + #endif /* _SALIBELF_H_ */ diff --git a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c index 8f8ce28be1e7..153ea1e73139 100644 --- a/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c +++ b/src/jdk.hotspot.agent/linux/native/libsaproc/symtab.c @@ -49,245 +49,20 @@ typedef struct symtab { } symtab_t; -// Directory that contains global debuginfo files. In theory it -// should be possible to change this, but in a Java environment there -// is no obvious place to put a user interface to do it. Maybe this -// could be set with an environment variable. -static const char debug_file_directory[] = "/usr/lib/debug"; - -/* The CRC used in gnu_debuglink, retrieved from - http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files. */ -unsigned int gnu_debuglink_crc32 (unsigned int crc, - unsigned char *buf, size_t len) -{ - static const unsigned int crc32_table[256] = - { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, - 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, - 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, - 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, - 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, - 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, - 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, - 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, - 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, - 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, - 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, - 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, - 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, - 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, - 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, - 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, - 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, - 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, - 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, - 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, - 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, - 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, - 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, - 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, - 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, - 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, - 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, - 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, - 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, - 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, - 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, - 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, - 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, - 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, - 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, - 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, - 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, - 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, - 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, - 0x2d02ef8d - }; - unsigned char *end; - - crc = ~crc & 0xffffffff; - for (end = buf + len; buf < end; ++buf) - crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8); - return ~crc & 0xffffffff; -} - -/* Open a debuginfo file and check its CRC. If it exists and the CRC - matches return its fd. */ -static int -open_debug_file (const char *pathname, unsigned int crc) -{ - unsigned int file_crc = 0; - unsigned char buffer[8 * 1024]; - - int fd = pathmap_open(pathname); - - if (fd < 0) - return -1; - - lseek(fd, 0, SEEK_SET); - - for (;;) { - int len = read(fd, buffer, sizeof buffer); - if (len <= 0) - break; - file_crc = gnu_debuglink_crc32(file_crc, buffer, len); - } - - if (crc == file_crc) - return fd; - else { - close(fd); - return -1; - } -} - -/* Look for a ".gnu_debuglink" section. If one exists, try to open a - suitable debuginfo file. */ -static int open_file_from_debug_link(const char *name, - int fd, - ELF_EHDR *ehdr, - struct elf_section *scn_cache) -{ - int debug_fd; - struct elf_section *debug_link = find_section_by_name(".gnu_debuglink", fd, ehdr, - scn_cache); - if (debug_link == NULL) - return -1; - char *debug_filename = debug_link->c_data; - int offset = (strlen(debug_filename) + 4) >> 2; - static unsigned int crc; - crc = ((unsigned int*)debug_link->c_data)[offset]; - char *debug_pathname = malloc(strlen(debug_filename) - + strlen(name) - + strlen(".debug/") - + strlen(debug_file_directory) - + 2); - if (debug_pathname == NULL) { - return -1; - } - strcpy(debug_pathname, name); - char *last_slash = strrchr(debug_pathname, '/'); - if (last_slash == NULL) { - free(debug_pathname); - return -1; - } - - /* Look in the same directory as the object. */ - strcpy(last_slash+1, debug_filename); - debug_fd = open_debug_file(debug_pathname, crc); - if (debug_fd >= 0) { - free(debug_pathname); - return debug_fd; - } - - /* Look in a subdirectory named ".debug". */ - strcpy(last_slash+1, ".debug/"); - strcat(last_slash, debug_filename); - - debug_fd = open_debug_file(debug_pathname, crc); - if (debug_fd >= 0) { - free(debug_pathname); - return debug_fd; - } - - /* Look in /usr/lib/debug + the full pathname. */ - strcpy(debug_pathname, debug_file_directory); - strcat(debug_pathname, name); - last_slash = strrchr(debug_pathname, '/'); - strcpy(last_slash+1, debug_filename); - - debug_fd = open_debug_file(debug_pathname, crc); - if (debug_fd >= 0) { - free(debug_pathname); - return debug_fd; - } - - free(debug_pathname); - return -1; -} - static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo); -/* Look for a ".gnu_debuglink" section. If one exists, try to open a - suitable debuginfo file and read a symbol table from it. */ -static struct symtab *build_symtab_from_debug_link(const char *name, - int fd, - ELF_EHDR *ehdr, - struct elf_section *scn_cache) -{ - fd = open_file_from_debug_link(name, fd, ehdr, scn_cache); - - if (fd >= 0) { - struct symtab *symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false); - close(fd); +/* Try to open a suitable debuginfo file and read a symbol table from it. */ +static struct symtab *build_symtab_from_debuginfo(const char* filename, int fd) { + int debug_fd = open_debuginfo(filename, fd); + if (debug_fd >= 0) { + struct symtab *symtab = build_symtab_internal(debug_fd, NULL, /* try_debuginfo */ false); + close(debug_fd); return symtab; } return NULL; } -// Given a build_id, find the associated debuginfo file -static char * -build_id_to_debug_filename (size_t size, unsigned char *data) -{ - char *filename, *s; - - filename = malloc(strlen (debug_file_directory) + (sizeof "/.build-id/" - 1) + 1 - + 2 * size + (sizeof ".debug" - 1) + 1); - if (filename == NULL) { - return NULL; - } - s = filename + sprintf (filename, "%s/.build-id/", debug_file_directory); - if (size > 0) - { - size--; - s += sprintf (s, "%02x", *data++); - } - if (size > 0) - *s++ = '/'; - while (size-- > 0) - s += sprintf (s, "%02x", *data++); - strcpy (s, ".debug"); - - return filename; -} - -// Read a build ID note. Try to open any associated debuginfo file -// and return its symtab -static struct symtab* build_symtab_from_build_id(Elf64_Nhdr *note) -{ - int fd; - struct symtab *symtab = NULL; - - unsigned char *bytes - = (unsigned char*)(note+1) + note->n_namesz; - char *filename - = (build_id_to_debug_filename (note->n_descsz, bytes)); - if (filename == NULL) { - return NULL; - } - fd = pathmap_open(filename); - if (fd >= 0) { - symtab = build_symtab_internal(fd, NULL, /* try_debuginfo */ false); - close(fd); - } - free(filename); - - return symtab; -} - // read symbol table from given fd. If try_debuginfo) is true, also // try to open an associated debuginfo file static struct symtab* build_symtab_internal(int fd, const char *filename, bool try_debuginfo) { @@ -464,28 +239,7 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t // the debuginfo file. We stash a copy of the old symtab in case // there is no debuginfo. struct symtab* prev_symtab = symtab; - symtab = NULL; - -#ifdef NT_GNU_BUILD_ID - // First we look for a Build ID - for (cursct = shbuf, cnt = 0; - symtab == NULL && cnt < ehdr.e_shnum; - cnt++) { - if (cursct->sh_type == SHT_NOTE) { - Elf64_Nhdr *note = (Elf64_Nhdr *)scn_cache[cnt].c_data; - if (note->n_type == NT_GNU_BUILD_ID) { - symtab = build_symtab_from_build_id(note); - } - } - cursct++; - } -#endif - - // Then, if that doesn't work, the debug link - if (symtab == NULL) { - symtab = build_symtab_from_debug_link(filename, fd, &ehdr, - scn_cache); - } + symtab = build_symtab_from_debuginfo(filename, fd); // If we still haven't found a symtab, use the object's own symtab. if (symtab != NULL) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java index 9a6c982eb3dc..dfb3966046d2 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java @@ -140,7 +140,6 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); - addThemeSwitcher(target); break; case MODULE: addOverviewLink(target); @@ -152,7 +151,6 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); - addThemeSwitcher(target); break; case PACKAGE: addOverviewLink(target); @@ -171,7 +169,6 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); - addThemeSwitcher(target); break; case CLASS: addOverviewLink(target); @@ -190,7 +187,6 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); - addThemeSwitcher(target); break; case USE: addOverviewLink(target); @@ -215,7 +211,6 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); - addThemeSwitcher(target); break; case TREE: addOverviewLink(target); @@ -234,7 +229,6 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); - addThemeSwitcher(target); break; case DEPRECATED: case INDEX: @@ -277,7 +271,6 @@ private void addMainNavLinks(Content target) { } else { addHelpLink(target); } - addThemeSwitcher(target); break; case ALL_CLASSES: case ALL_PACKAGES: @@ -295,7 +288,6 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); - addThemeSwitcher(target); break; case DOC_FILE: addOverviewLink(target); @@ -322,7 +314,6 @@ private void addMainNavLinks(Content target) { addIndexLink(target); addSearchLink(target); addHelpLink(target); - addThemeSwitcher(target); break; default: break; @@ -524,37 +515,6 @@ private void addHelpLink(Content target) { } } - private void addThemeSwitcher(Content target) { - var selectTheme = contents.getContent("doclet.theme.select_theme"); - target.add(HtmlTree.LI(HtmlTree.BUTTON(HtmlIds.THEME_BUTTON) - .put(HtmlAttr.ARIA_LABEL, selectTheme.toString()) - .put(HtmlAttr.TITLE, selectTheme.toString()))); - } - - private void addThemePanel(Content target) { - var selectTheme = contents.getContent("doclet.theme.select_theme"); - target.add(HtmlTree.DIV(HtmlIds.THEME_PANEL) - .add(HtmlTree.DIV(HtmlStyles.panelHeading, selectTheme)) - .add(HtmlTree.DIV(HtmlTree.LABEL(HtmlIds.THEME_LIGHT.name(), Text.EMPTY) - .add(HtmlTree.INPUT(HtmlAttr.InputType.RADIO, HtmlIds.THEME_LIGHT) - .put(HtmlAttr.NAME, "theme").put(HtmlAttr.VALUE, HtmlIds.THEME_LIGHT.name())) - .add(HtmlTree.SPAN(contents.getContent("doclet.theme.light")))) - .add(HtmlTree.LABEL(HtmlIds.THEME_DARK.name(), Text.EMPTY) - .add(HtmlTree.INPUT(HtmlAttr.InputType.RADIO, HtmlIds.THEME_DARK) - .put(HtmlAttr.NAME, "theme").put(HtmlAttr.VALUE, HtmlIds.THEME_DARK.name())) - .add(HtmlTree.SPAN(contents.getContent("doclet.theme.dark")))) - .add(HtmlTree.LABEL(HtmlIds.THEME_OS.name(), Text.EMPTY) - .add(HtmlTree.INPUT(HtmlAttr.InputType.RADIO, HtmlIds.THEME_OS) - .put(HtmlAttr.NAME, "theme").put(HtmlAttr.VALUE, HtmlIds.THEME_OS.name())) - .add(HtmlTree.SPAN(contents.getContent("doclet.theme.system"))))) - .add(HtmlTree.DIV(HtmlTree.LABEL(HtmlId.of("underline-links").name(), - HtmlTree.INPUT(HtmlAttr.InputType.CHECKBOX, HtmlId.of("underline-links")) - .put(HtmlAttr.ONCLICK, "")) - .add(HtmlTree.SPAN(contents.getContent("doclet.theme.underline_links"))))) - .add(HtmlTree.BUTTON(HtmlId.of("theme-panel-close-button")))); - target.add(new Script().append("initTheme();\n").asContent()); - } - private void addSearch(Content target) { var resources = configuration.getDocResources(); var placeholder = resources.getText("doclet.search_placeholder"); @@ -642,7 +602,7 @@ public Content getContent() { .put(HtmlAttr.TITLE, rowListTitle); addMainNavLinks(navList); navContent.add(navList); - addThemePanel(navContent); + navList.add(new Script().append("initTheme();").asContent()); var aboutDiv = HtmlTree.DIV(HtmlStyles.aboutLanguage, aboutContent); navContent.add(aboutDiv); navigationBar.add(HtmlTree.DIV(HtmlStyles.topNav, navContent).setId(HtmlIds.NAVBAR_TOP)); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template index b2c8ecdd0724..e00b8682811f 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/script.js.template @@ -26,6 +26,11 @@ const UNDERLINE_LINKS = "underline-links"; const linkIcon = "##REPLACE:doclet.Link_icon##"; const linkToSection = "##REPLACE:doclet.Link_to_section##"; const toggleMemberListing = "##REPLACE:doclet.Toggle_member_listing##"; +const selectTheme = "##REPLACE:doclet.theme.select_theme##"; +const lightThemeLabel = "##REPLACE:doclet.theme.light##"; +const darkThemeLabel = "##REPLACE:doclet.theme.dark##"; +const systemThemeLabel = "##REPLACE:doclet.theme.system##"; +const underlineLinksLabel = "##REPLACE:doclet.theme.underline_links##"; const sortLexicalLabel = "##REPLACE:doclet.Sort_lexicographically##"; const sortSourceLabel = "##REPLACE:doclet.Sort_by_source_order##"; @@ -248,6 +253,9 @@ function switchCopyLabel(button, span) { }, 100); }, 1900); } +/* + * Sidebar filter input + */ function makeFilterWidget(sidebar, updateToc) { if (!sidebar) { return null; @@ -324,33 +332,136 @@ function makeFilterWidget(sidebar, updateToc) { return sidebar; } -const osDarkTheme = window.matchMedia("(prefers-color-scheme: dark)"); -function getTheme() { - return [ - localStorage.getItem(THEME) ?? THEME_LIGHT, - localStorage.getItem(UNDERLINE_LINKS) - ]; -} -function setTheme([theme, underlineLinks]) { - if (theme === THEME_OS) { - theme = osDarkTheme.matches ? THEME_DARK : THEME_LIGHT; +/* + * Theme support + */ +function initTheme() { + const template = document.createElement("template"); + template.innerHTML = + `

  • + +
    +
    ${selectTheme}
    +
    + + + +
    +
    + +
    + +
    +
  • `; + + const themeUI = template.content.firstElementChild; + const themeButton = themeUI.querySelector("button#theme-button"); + const themePanel = themeUI.querySelector("div#theme-panel"); + var themePanelVisible = false; + const osDarkTheme = window.matchMedia("(prefers-color-scheme: dark)"); + let [currentTheme, underlineLinks] = getTheme(); + setTheme(currentTheme, underlineLinks); + + function getTheme() { + return [ + localStorage.getItem(THEME) ?? THEME_LIGHT, + localStorage.getItem(UNDERLINE_LINKS) + ]; + } + function setTheme(theme, underlineLinks) { + if (theme === THEME_OS) { + theme = osDarkTheme.matches ? THEME_DARK : THEME_LIGHT; + } + document.documentElement.setAttribute("data-theme", theme); + if (underlineLinks) { + document.documentElement.setAttribute("data-underline-links", underlineLinks); + } else { + themePanel.querySelector("input#underline-links").checked = (theme === THEME_DARK); + } } - document.documentElement.setAttribute("data-theme", theme); - if (underlineLinks) { - document.documentElement.setAttribute("data-underline-links", underlineLinks); - } else { - document.getElementById(UNDERLINE_LINKS).checked = (theme === THEME_DARK); + osDarkTheme.addEventListener("change", e => { + if (currentTheme === THEME_OS) { + setTheme(currentTheme, underlineLinks); + } + }); + themePanel.querySelectorAll("input").forEach(input => { + if (input.id === currentTheme) { + input.checked = true; + } else if (input.id === UNDERLINE_LINKS) { + input.checked = (underlineLinks === "on" || + (!underlineLinks && document.documentElement.getAttribute("data-theme") === THEME_DARK)); + input.addEventListener("change", e => { + underlineLinks = e.target.checked ? "on" : "off"; + localStorage.setItem(UNDERLINE_LINKS, underlineLinks); + setTheme(currentTheme, underlineLinks); + }); + } + if (input.name === "theme") { + input.addEventListener("change", e => { + currentTheme = e.target.value; + localStorage.setItem(THEME, e.target.value); + setTheme(currentTheme, underlineLinks); + }); + } + }); + + themeButton.addEventListener("click", e => { + if (!themePanelVisible) { + let {x, y} = themeButton.getBoundingClientRect(); + let expanded = x < y; + themePanel.style.display = "block"; + if (document.documentElement.clientHeight - themePanel.offsetHeight < y) { + themePanel.style.top = ""; + themePanel.style.bottom = "4px"; + } else { + themePanel.style.top = y + (expanded ? 0 : 36) + "px"; + themePanel.style.bottom = ""; + } + const desiredLeft = x + (expanded ? 36 : 0); + const maxLeft = document.documentElement.clientWidth - themePanel.offsetWidth - 4; + themePanel.style.left = Math.max(4, Math.min(desiredLeft, maxLeft)) + "px"; + + themeButton.setAttribute("aria-expanded", "true"); + themePanelVisible = true; + e.stopPropagation(); + } + }); + + function closeThemePanel() { + if (themePanelVisible) { + themePanel.style.removeProperty("display"); + themeButton.setAttribute("aria-expanded", "false"); + themePanelVisible = false; + } } -} -function initTheme() { - setTheme(getTheme()); + themeUI.querySelector("button#theme-panel-close-button")?.addEventListener("click", e => { + closeThemePanel(); + }); + themePanel.addEventListener("focusout", e => { + if (e.relatedTarget && !themePanel.contains(e.relatedTarget) && !themeButton.contains(e.relatedTarget)) { + closeThemePanel(); + } + }); + document.body.addEventListener("click", (e) => { + if (e.target && !themePanel.contains(e.target)) { + closeThemePanel(); + } + }); + document.body.addEventListener("keydown", (e) => { + if (e.key === "Escape" || e.key === "Enter") { + closeThemePanel(); + } + }); + document.currentScript.parentElement.appendChild(themeUI); } function setTopMargin() { // Dynamically set scroll margin to accomodate for draft header - var headerHeight = Math.ceil(document.querySelector("header").offsetHeight); - document.querySelector(":root") - .style.setProperty("--nav-height", headerHeight + "px"); + let header = document.querySelector("header"); + if (header && getComputedStyle(header).position === "sticky") { + var headerHeight = Math.ceil(header.offsetHeight); + document.querySelector(":root").style.setProperty("--nav-height", headerHeight + "px"); + } } document.addEventListener("readystatechange", (e) => { @@ -382,73 +493,7 @@ document.addEventListener("DOMContentLoaded", function(e) { const mainnav = document.querySelector("div#navbar-top ul.nav-list"); const toggleButton = document.querySelector("button#navbar-toggle-button"); const tocMenu = sidebar ? sidebar.cloneNode(true) : null; - const themeButton = document.querySelector("button#theme-button"); - const themePanel = document.querySelector("div#theme-panel"); - var themePanelVisible = false; - themeButton.addEventListener("click", e => { - if (!themePanelVisible) { - let {x, y} = themeButton.getBoundingClientRect(); - themePanel.style.display = "block"; - if (window.innerHeight - themePanel.offsetHeight < y) { - themePanel.style.top = ""; - themePanel.style.bottom = "4px"; - } else { - themePanel.style.top = y + (expanded ? 0 : 36) + "px"; - themePanel.style.bottom = ""; - } - themePanel.style.left = x + (expanded ? 36 : 0) + "px"; - themeButton.setAttribute("aria-expanded", "true"); - themePanelVisible = true; - e.stopPropagation(); - } - }); - function closeThemePanel(e) { - if (themePanelVisible && (!e || !themePanel.contains(e.target))) { - themePanel.style.removeProperty("display"); - themeButton.setAttribute("aria-expanded", "false"); - themePanelVisible = false; - } - } - document.getElementById("theme-panel-close-button").addEventListener("click", e => { - closeThemePanel(); - }); - var [currentTheme, underlineLinks] = getTheme(); - osDarkTheme.addEventListener("change", e => { - if (currentTheme === THEME_OS) { - setTheme([currentTheme, underlineLinks]); - } - }); - themePanel.querySelectorAll("input").forEach(input => { - input.removeAttribute("disabled"); - if (input.id === currentTheme) { - input.checked = true; - } else if (input.id === UNDERLINE_LINKS) { - input.checked = (underlineLinks === "on" || - (!underlineLinks && document.documentElement.getAttribute("data-theme") === THEME_DARK)); - input.addEventListener("change", e => { - underlineLinks = e.target.checked ? "on" : "off"; - localStorage.setItem(UNDERLINE_LINKS, underlineLinks); - setTheme([currentTheme, underlineLinks]); - }); - } - if (input.name === "theme") { - input.addEventListener("change", e => { - currentTheme = e.target.value; - localStorage.setItem(THEME, e.target.value); - setTheme([currentTheme, underlineLinks]); - }); - } - }); - themePanel.addEventListener("focusout", e => { - if (e.relatedTarget && !themePanel.contains(e.relatedTarget) && !themeButton.contains(e.relatedTarget)) { - closeThemePanel(); - } - }); - themePanel.addEventListener("keydown", e => { - if (e.key === "Escape" || e.key === "Enter") { - closeThemePanel(); - } - }); + makeFilterWidget(sidebar, updateToc); if (tocMenu) { document.querySelector("div#navbar-top").appendChild(tocMenu); @@ -463,7 +508,6 @@ document.addEventListener("DOMContentLoaded", function(e) { return; } if (!isInput(e.target) && keymap.has(e.key)) { - closeThemePanel(); var elem = keymap.get(e.key); if (elem === filterInput && !elem.offsetParent) { elem = getVisibleFilterInput(true); @@ -472,7 +516,6 @@ document.addEventListener("DOMContentLoaded", function(e) { elem.select(); e.preventDefault(); } else if (e.key === "Escape") { - closeThemePanel(); var filter = getVisibleFilterInput(false); if (e.target === filter) { resetInput(filter, e, true); @@ -486,7 +529,6 @@ document.addEventListener("DOMContentLoaded", function(e) { var windowWidth; var bodyHeight; function collapse() { - closeThemePanel(); if (expanded) { mainnav.removeAttribute("style"); if (tocMenu) { @@ -542,7 +584,7 @@ document.addEventListener("DOMContentLoaded", function(e) { return menuInput; } } - toggleButton.addEventListener("click", (e) => { + toggleButton?.addEventListener("click", (e) => { if (expanded) { collapse(); } else { @@ -555,14 +597,14 @@ document.addEventListener("DOMContentLoaded", function(e) { }); } document.querySelector("main").addEventListener("click", collapse); - document.querySelector("body").addEventListener("click", closeThemePanel); document.querySelectorAll("h1, h2, h3, h4, h5, h6") .forEach((hdr, idx) => { // Create anchor links for headers with an associated id attribute - var id = hdr.parentElement.getAttribute("id") || hdr.getAttribute("id") - || (hdr.querySelector("a") && hdr.querySelector("a").getAttribute("id")); + const id = hdr.id + || hdr.querySelector("a")?.id + || (hdr.parentElement?.firstElementChild === hdr && hdr.parentElement.id); if (id) { - var template = document.createElement('template'); + const template = document.createElement('template'); template.innerHTML =" "
                     + linkIcon + ""; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java b/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java index a8de95921407..de2f28d76145 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/EventSettings.java @@ -96,8 +96,8 @@ public AnnotationElement newAnnotation(Type annotationType, List values, } @Override - public ValueDescriptor newValueDescriptor(String name, Type fieldType, List annos, int dimension, boolean constantPool, String fieldName) { - return new ValueDescriptor(fieldType, name, annos, dimension, constantPool, fieldName); + public ValueDescriptor newValueDescriptor(String name, Type fieldType, List annos, int dimension, boolean constantPool) { + return new ValueDescriptor(fieldType, name, annos, dimension, constantPool); } @Override @@ -125,11 +125,6 @@ public void setAnnotations(SettingDescriptor s, List a) { s.setAnnotations(a); } - @Override - public String getFieldName(ValueDescriptor v) { - return v.getJavaFieldName(); - } - @Override public ValueDescriptor newValueDescriptor(Class type, String name) { return new ValueDescriptor(type, name, List.of(), true); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java b/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java index 9994b689d093..6fa1cf169fac 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/ValueDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -51,12 +51,11 @@ public final class ValueDescriptor { private final String name; private final boolean isArray; private final boolean constantPool; - private final String javaFieldName; private String label = UNKNOWN; private String contentType = UNKNOWN; // package private, invoked by jdk.internal. - ValueDescriptor(Type type, String name, List annotations, int dimension, boolean constantPool, String fieldName) { + ValueDescriptor(Type type, String name, List annotations, int dimension, boolean constantPool) { Objects.requireNonNull(annotations); if (dimension < 0) { throw new IllegalArgumentException("Dimension must be positive"); @@ -66,7 +65,6 @@ public final class ValueDescriptor { this.isArray = dimension > 0; this.constantPool = constantPool; this.annotationConstruct = new AnnotationConstruct(annotations); - this.javaFieldName = fieldName; } /** @@ -137,7 +135,6 @@ public ValueDescriptor(Class type, String name, List annot this(type, name, List.copyOf(annotations), false); } - ValueDescriptor(Class type, String name, List annotations, boolean allowArray) { Objects.requireNonNull(type, "type"); Objects.requireNonNull(name, "name"); @@ -151,7 +148,6 @@ public ValueDescriptor(Class type, String name, List annot Utils.ensureJavaIdentifier(name); this.type = Objects.requireNonNull(Utils.getValidType(Objects.requireNonNull(type), Objects.requireNonNull(name))); this.annotationConstruct = new AnnotationConstruct(annotations); - this.javaFieldName = name; // Needed for dynamic events this.isArray = type.isArray(); // Assume we always want to store String and Thread in constant pool this.constantPool = type == Class.class || type == Thread.class; @@ -321,11 +317,6 @@ boolean isConstantPool() { return constantPool; } - // package private - String getJavaFieldName() { - return javaFieldName; - } - // package private boolean isUnsigned() { return annotationConstruct.hasUnsigned(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java index b21b539cab87..a784e21b692f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -115,10 +115,6 @@ final String getLastValue() { return lastValue; } - final SettingControl getSettingControl() { - return delegate; - } - boolean isVisible(boolean hasEventHook) { if (isType(ThresholdSetting.class)) { return !hasEventHook; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java index 621c879f712e..3391a9454330 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/EventControl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -66,7 +66,6 @@ public final class EventControl { record NamedControl(String name, Control control) { } - static final String FIELD_SETTING_PREFIX = "setting"; private static final Type TYPE_ENABLED = TypeLibrary.createType(EnabledSetting.class); private static final Type TYPE_THRESHOLD = TypeLibrary.createType(ThresholdSetting.class); private static final Type TYPE_STACK_TRACE = TypeLibrary.createType(StackTraceSetting.class); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java index 79bc614545ed..d859c796ee67 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JDKEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -47,7 +47,6 @@ import jdk.jfr.internal.periodic.PeriodicEvents; import jdk.jfr.internal.settings.MethodSetting; import jdk.jfr.internal.tracing.PlatformTracer; -import jdk.jfr.tracing.MethodTracer; public final class JDKEvents { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java index d3f50567c23d..c2dbffd31a93 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/JVM.java @@ -39,8 +39,6 @@ * */ public final class JVM { - private static final JVM jvm = new JVM(); - static final long RESERVED_CLASS_ID_LIMIT = 500; /* @@ -165,13 +163,6 @@ public final class JVM { */ public static native long getThreadId(Thread t); - /** - * Frequency, ticks per second - * - * @return frequency - */ - public static native long getTicksFrequency(); - /** * Returns the same clock that sets the start time of a chunk (in nanos). */ @@ -326,16 +317,6 @@ public final class JVM { */ public static native void setForceInstrumentation(boolean force); - /** - * Turn on/off compressed integers. - * - * @param compressed true if compressed integers should be used, false - * otherwise. - * - * @throws IllegalStateException if state can't be changed. - */ - public static native void setCompressedIntegers(boolean compressed) throws IllegalStateException; - /** * Set stack depth. * @@ -523,19 +504,6 @@ public final class JVM { public static native void uncaughtException(Thread thread, Throwable t); - /** - * Sets cutoff for event. - * - * Determines how long the event should be allowed to run. - * - * Long.MAXIMUM_VALUE = no limit - * - * @param eventTypeId the id of the event type - * @param cutoffTicks cutoff in ticks, - * @return true, if it could be set - */ - public static native boolean setCutoff(long eventTypeId, long cutoffTicks); - /** * Sets the event emission rate in event sample size per time unit. * diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java index 2d1332aed06b..d5a4cc34fcf8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataLoader.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -265,7 +265,7 @@ private void addFields(Map lookup, Map if (!"package".equals(f.name) && !"java.lang.Class".equals(te.name)) { Utils.ensureJavaIdentifier(f.name); } - type.add(PrivateAccess.getInstance().newValueDescriptor(f.name, fieldType, aes, f.array ? 1 : 0, f.constantPool, null)); + type.add(PrivateAccess.getInstance().newValueDescriptor(f.name, fieldType, aes, f.array ? 1 : 0, f.constantPool)); } } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java index dd0a68e0ee08..40712dee67b7 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataReader.java @@ -242,7 +242,7 @@ private void defineTypes(Element metadata) { boolean constantPool = fieldElement.attribute(ATTRIBUTE_CONSTANT_POOL) != null; // Add annotation later, because they may refer to undefined // types at this stage - t.add(PrivateAccess.getInstance().newValueDescriptor(name, fieldType, new ArrayList<>(), (int) dimension, constantPool, null)); + t.add(PrivateAccess.getInstance().newValueDescriptor(name, fieldType, new ArrayList<>(), (int) dimension, constantPool)); } t.trimFields(); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java index 22d55e6e99fc..4047bb6c8986 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/MetadataRepository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -28,8 +28,6 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; import java.time.Instant; import java.util.ArrayList; import java.util.Collections; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java index 8d13026d3899..f48a3836e73e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecorder.java @@ -333,7 +333,6 @@ synchronized void stop(PlatformRecording recording) { } } OldObjectSample.emit(recording); - recording.setFinalStartnanos(JVMSupport.getChunkStartNanos()); if (endPhysical) { PeriodicEvents.doChunkEnd(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java index ee30e2ceca4f..8fbb52ef7514 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PlatformRecording.java @@ -53,7 +53,6 @@ import java.util.TimerTask; import java.util.TreeMap; -import jdk.jfr.Configuration; import jdk.jfr.FlightRecorderListener; import jdk.jfr.Recording; import jdk.jfr.RecordingState; @@ -91,7 +90,6 @@ public final class PlatformRecording implements AutoCloseable { private TimerTask startTask; private boolean shouldWriteActiveRecordingEvent = true; private Duration flushInterval = Duration.ofSeconds(1); - private long finalStartChunkNanos = Long.MIN_VALUE; private long startNanos = -1; PlatformRecording(PlatformRecorder recorder, long id) { @@ -551,10 +549,6 @@ public String toString() { return getName() + " (id=" + getId() + ") " + getState(); } - public void setConfiguration(Configuration c) { - setSettings(c.getSettings()); - } - public void setMaxAge(Duration maxAge) { synchronized (recorder) { if (getState() == RecordingState.CLOSED) { @@ -884,14 +878,6 @@ public long getStartNanos() { return startNanos; } - public long getFinalChunkStartNanos() { - return finalStartChunkNanos; - } - - public void setFinalStartnanos(long chunkStartNanos) { - this.finalStartChunkNanos = chunkStartNanos; - } - public void removeBefore(Instant timestamp) { synchronized (recorder) { while (!chunks.isEmpty()) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java index b30e50ff4f3a..b5c31c8d31fd 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/PrivateAccess.java @@ -74,7 +74,7 @@ public static void setPrivateAccess(PrivateAccess pa) { public abstract AnnotationElement newAnnotation(Type annotationType, List values, boolean boot); - public abstract ValueDescriptor newValueDescriptor(String name, Type fieldType, List annotations, int dimension, boolean constantPool, String fieldName); + public abstract ValueDescriptor newValueDescriptor(String name, Type fieldType, List annotations, int dimension, boolean constantPool); public abstract PlatformRecording getPlatformRecording(Recording r); @@ -82,8 +82,6 @@ public static void setPrivateAccess(PrivateAccess pa) { public abstract boolean isConstantPool(ValueDescriptor v); - public abstract String getFieldName(ValueDescriptor v); - public abstract ValueDescriptor newValueDescriptor(Class type, String name); public abstract SettingDescriptor newSettingDescriptor(Type type, String name, String def, List aes); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java index 80edba97e59b..d3fdc745331e 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Type.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -214,10 +214,6 @@ private boolean calculateSimpleType() { return superType == null; } - public boolean isDefinedByJVM() { - return id < JVM.RESERVED_CLASS_ID_LIMIT; - } - public void setFields(List fields) { this.fields = List.copyOf(fields); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java index aabd9a094bc1..42d12d098f28 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/TypeLibrary.java @@ -31,7 +31,6 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; @@ -77,26 +76,23 @@ private TypeLibrary() { private static ValueDescriptor createStartTimeField() { var annos = createStandardAnnotations("Start Time", null); annos.add(new jdk.jfr.AnnotationElement(Timestamp.class, Timestamp.TICKS)); - return PrivateAccess.getInstance().newValueDescriptor(ImplicitFields.START_TIME, Type.LONG, annos, 0, false, - ImplicitFields.START_TIME); + return PrivateAccess.getInstance().newValueDescriptor(ImplicitFields.START_TIME, Type.LONG, annos, 0, false); } private static ValueDescriptor createStackTraceField() { var annos = createStandardAnnotations("Stack Trace", "Stack Trace starting from the method the event was committed in"); - return PrivateAccess.getInstance().newValueDescriptor(ImplicitFields.STACK_TRACE, Type.STACK_TRACE, annos, 0, true, - ImplicitFields.STACK_TRACE); + return PrivateAccess.getInstance().newValueDescriptor(ImplicitFields.STACK_TRACE, Type.STACK_TRACE, annos, 0, true); } private static ValueDescriptor createThreadField() { var annos = createStandardAnnotations("Event Thread", "Thread in which event was committed in"); - return PrivateAccess.getInstance().newValueDescriptor(ImplicitFields.EVENT_THREAD, Type.THREAD, annos, 0, true, - ImplicitFields.EVENT_THREAD); + return PrivateAccess.getInstance().newValueDescriptor(ImplicitFields.EVENT_THREAD, Type.THREAD, annos, 0, true); } private static ValueDescriptor createDurationField() { var annos = createStandardAnnotations("Duration", null); annos.add(new jdk.jfr.AnnotationElement(Timespan.class, Timespan.TICKS)); - return PrivateAccess.getInstance().newValueDescriptor(ImplicitFields.DURATION, Type.LONG, annos, 0, false, ImplicitFields.DURATION); + return PrivateAccess.getInstance().newValueDescriptor(ImplicitFields.DURATION, Type.LONG, annos, 0, false); } public static synchronized void initialize() { @@ -378,9 +374,8 @@ private static ValueDescriptor createField(Field field) { Class fieldType = field.getType(); boolean constantPool = Thread.class == fieldType || fieldType == Class.class; Type type = createType(fieldType); - String fieldName = field.getName(); Name name = field.getAnnotation(Name.class); - String useName = fieldName; + String useName = field.getName(); if (name != null) { useName = Utils.validJavaIdentifier(name.value(), useName); } @@ -391,7 +386,7 @@ private static ValueDescriptor createField(Field field) { ans.add(ae); } } - return PrivateAccess.getInstance().newValueDescriptor(useName, type, ans, 0, constantPool, fieldName); + return PrivateAccess.getInstance().newValueDescriptor(useName, type, ans, 0, constantPool); } private static List resolveRepeatedAnnotations(Annotation[] annotations) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java index 57dacb955032..ce611904402c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/EventParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -104,10 +104,6 @@ public void setEnabled(boolean enabled) { this.enabled = enabled; } - public boolean isEnabled() { - return enabled; - } - @Override public RecordedEvent parse(RecordingInput input) throws IOException { if (!enabled) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java index a60117fe316c..3cac3105b07a 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/OngoingStream.java @@ -31,7 +31,6 @@ import jdk.jfr.Recording; import jdk.jfr.RecordingState; -import jdk.jfr.internal.SecuritySupport; import jdk.jfr.internal.management.EventByteStream; import jdk.jfr.internal.management.HiddenWait; import jdk.jfr.internal.management.ManagementSupport; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java index c973dadb3b7f..134afc03d535 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ParserFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -90,7 +90,7 @@ private Parser createParser(ValueDescriptor v, boolean event) throws IOException boolean constantPool = PrivateAccess.getInstance().isConstantPool(v); if (v.isArray()) { Type valueType = PrivateAccess.getInstance().getType(v); - ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool, null); + ValueDescriptor element = PrivateAccess.getInstance().newValueDescriptor(v.getName(), valueType, v.getAnnotationElements(), 0, constantPool); return new ArrayParser(createParser(element, event)); } long id = v.getTypeId(); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java index 701bc0396c6a..edeccb77a117 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, 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,14 +253,6 @@ private Recording findRecordingByName(String name) throws DCmdException { throw new DCmdException("Could not find %s.\n\nUse JFR.check without options to see list of all available recordings.", name); } - protected final String exampleRepository() { - if ("\r\n".equals(System.lineSeparator())) { - return "C:\\Repositories"; - } else { - return "/Repositories"; - } - } - protected final String exampleFilename() { if ("\r\n".equals(System.lineSeparator())) { return "C:\\Users\\user\\recording.jfr"; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/event/EventWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/event/EventWriter.java index 8dbac99067a7..f35e297c39d8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/event/EventWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/event/EventWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -224,10 +224,6 @@ private int usedSize() { return (int) (currentPosition - startPosition); } - private void flush() { - flush(usedSize(), 0); - } - private void flush(int usedSize, int requestedSize) { JVM.flush(this, usedSize, requestedSize); } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/JFCModel.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/JFCModel.java index e0b5fb4a6f30..78d915f509ed 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/JFCModel.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/jfc/model/JFCModel.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, 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 @@ -140,10 +140,6 @@ public List getInputs() { return inputs; } - public XmlConfiguration getConfiguration() { - return configuration; - } - public LinkedHashMap getSettings() { LinkedHashMap result = new LinkedHashMap<>(); for (XmlEvent event : configuration.getEvents()) { diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Query.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Query.java index de316aad3543..d12d536892b4 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Query.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/Query.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -41,9 +41,6 @@ record Source(String name, Optional alias) { record Condition(String field, String value) { } - record Where(List conditions) { - } - record Property(String name, Consumer style) { } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableCell.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableCell.java index 7928eae2f4c4..62b10075e45f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableCell.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/query/TableCell.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 @@ -68,6 +68,7 @@ public void setPreferredWidth(int width) { public int getPreferredWidth() { return preferredWidth; } + public void addLine(String text) { int contentWidth = getContentWidth(); if (text.length() > contentWidth) { @@ -113,10 +114,6 @@ public int getContentSize() { return cellHeight * getContentWidth(); } - public List getLines() { - return lines; - } - private String truncate(String text, int size) { if (size < ELLIPSIS_LENGTH) { return ELLIPSIS.substring(0, ELLIPSIS_LENGTH - size); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java index e5093de781b6..814fb420bae4 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/settings/Throttler.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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,7 +26,7 @@ import java.util.Random; import java.util.concurrent.locks.ReentrantLock; -import jdk.jfr.internal.PlatformEventType; + public final class Throttler { private static final ThrottlerParameters DISABLED_PARAMETERS = new ThrottlerParameters(0, 0, 0); private static final long MILLIUNITS = 1000; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java index 36eff5b41064..c7299eb57e48 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/Assemble.java @@ -28,14 +28,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; -import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.Deque; import java.util.List; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java index 44aecf6413cf..c53c155d864f 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/PrettyWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -27,7 +27,6 @@ import java.io.IOException; import java.io.PrintWriter; -import java.lang.reflect.Array; import java.nio.file.Path; import java.time.Duration; import java.time.Instant; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/UserDataException.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/UserDataException.java deleted file mode 100644 index a21ae95f6713..000000000000 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/tool/UserDataException.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2018, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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 jdk.jfr.internal.tool; - -/** - * Exception that is thrown if there is something wrong with the input, for instance - * a file that can't be read or a numerical value that is out of range. - *

    - * When this exception is thrown, a user will typically not want to see the - * command line syntax, but instead information about what was wrong with the - * input. - */ -final class UserDataException extends Exception { - private static final long serialVersionUID = 6656457380115167810L; - /** - * The error message. - * - * The first letter should not be capitalized, so a context can be printed prior - * to the error message. - * - * @param errorMessage - */ - public UserDataException(String errorMessage) { - super(errorMessage); - } -} diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java index db832626deda..c770610bff06 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/Utils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,9 +26,6 @@ package jdk.jfr.internal.util; import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.RandomAccessFile; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; import java.lang.reflect.Array; @@ -135,11 +132,6 @@ private static Method getValueMethod(Class annotated) { } } - public static void touch(Path dumpFile) throws IOException { - RandomAccessFile raf = new RandomAccessFile(dumpFile.toFile(), "rw"); - raf.close(); - } - public static Class unboxType(Class t) { if (t == Integer.class) { return int.class; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java index cf112d3beb54..d004447f49d6 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/util/ValueParser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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 @@ -24,13 +24,6 @@ */ package jdk.jfr.internal.util; -import static java.util.concurrent.TimeUnit.DAYS; -import static java.util.concurrent.TimeUnit.HOURS; -import static java.util.concurrent.TimeUnit.MICROSECONDS; -import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static java.util.concurrent.TimeUnit.MINUTES; -import static java.util.concurrent.TimeUnit.SECONDS; - public final class ValueParser { public static final String INFINITY = "infinity"; public static final long MISSING = Long.MIN_VALUE; diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java index 1ed2a2a05aef..898e17a04639 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/DiskRepository.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -28,24 +28,18 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; import java.time.Duration; import java.time.Instant; import java.time.LocalDateTime; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Collections; import java.util.Deque; import java.util.Iterator; -import java.util.List; import java.util.Objects; -import java.util.Queue; import jdk.jfr.internal.management.ChunkFilename; import jdk.jfr.internal.management.ManagementSupport; @@ -92,10 +86,6 @@ private void destroy() { } } - public boolean isDead() { - return referenceCount == 0; - } - public Path path() { return path; } diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java index 467ff05e5132..019e176bd879 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBeanImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, 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,7 +61,6 @@ import javax.management.StandardEmitterMBean; import jdk.jfr.Configuration; -import jdk.jfr.EventType; import jdk.jfr.FlightRecorder; import jdk.jfr.FlightRecorderListener; import jdk.jfr.Recording; diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/RemoteRecordingStream.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/RemoteRecordingStream.java index a8752e159ad3..8ef8ef4a4ec5 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/RemoteRecordingStream.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/RemoteRecordingStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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 @@ -27,11 +27,8 @@ import java.io.IOException; import java.io.RandomAccessFile; -import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardOpenOption; import java.time.Duration; import java.time.Instant; import java.util.ArrayList; @@ -40,7 +37,6 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.concurrent.Future; import java.util.function.Consumer; import javax.management.JMX; import javax.management.MBeanServerConnection; @@ -50,15 +46,12 @@ import jdk.jfr.EventSettings; import jdk.jfr.EventType; import jdk.jfr.Recording; -import jdk.jfr.RecordingState; import jdk.jfr.consumer.EventStream; import jdk.jfr.consumer.MetadataEvent; import jdk.jfr.consumer.RecordedEvent; -import jdk.jfr.consumer.RecordingStream; import jdk.jfr.internal.management.EventSettingsModifier; import jdk.jfr.internal.management.ManagementSupport; import jdk.jfr.internal.management.StreamBarrier; -import jdk.management.jfr.DiskRepository.DiskChunk; import jdk.jfr.internal.management.EventByteStream; /** diff --git a/src/utils/hsdis/binutils/hsdis-binutils.c b/src/utils/hsdis/binutils/hsdis-binutils.c index 51877e85f468..666eb17ef0de 100644 --- a/src/utils/hsdis/binutils/hsdis-binutils.c +++ b/src/utils/hsdis/binutils/hsdis-binutils.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -591,7 +591,7 @@ static void init_disassemble_info_from_bfd(struct disassemble_info* dinfo, #endif dinfo->skip_zeroes = sizeof(void*) * 2; dinfo->skip_zeroes_at_end = sizeof(void*)-1; - dinfo->disassembler_needs_relocs = FALSE; + dinfo->disassembler_needs_relocs = false; if (bfd_big_endian(abfd)) dinfo->display_endian = dinfo->endian = BFD_ENDIAN_BIG; diff --git a/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp b/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp index 388c78074a07..917267c50817 100644 --- a/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1RegionMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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,12 +32,12 @@ class G1CommittedRegionMapSerial : public G1CommittedRegionMap { void verify_counts() { verify_num_active_regions(0, TestRegions, num_active_regions()); - verify_num_inactive_regions(0, TestRegions, num_inactive_regions()); + verify_num_pending_uncommit_regions(0, TestRegions, num_pending_uncommit_regions()); } protected: void guarantee_mt_safety_active() const { } - void guarantee_mt_safety_inactive() const { } + void guarantee_mt_safety_pending_uncommit() const { } }; static bool mutate() { @@ -78,7 +78,7 @@ static void random_deactivate(G1CommittedRegionMap* map) { static void random_uncommit_or_reactive(G1CommittedRegionMap* map) { uint current_offset = 0; do { - G1HeapRegionRange current = map->next_inactive_range(current_offset); + G1HeapRegionRange current = map->next_pending_uncommit_range(current_offset); // Randomly either reactivate or uncommit if (mutate()) { map->reactivate(current.start(), current.end()); @@ -124,6 +124,6 @@ TEST(G1CommittedRegionMapTest, serial) { serial_map.verify_counts(); random_activate_free(&serial_map); serial_map.verify_counts(); - ASSERT_EQ(serial_map.num_inactive_regions(), 0u); + ASSERT_EQ(serial_map.num_pending_uncommit_regions(), 0u); } } diff --git a/test/hotspot/gtest/riscv/test_assembler_riscv.cpp b/test/hotspot/gtest/riscv/test_assembler_riscv.cpp index 6281144fed63..40fb2488cfc4 100644 --- a/test/hotspot/gtest/riscv/test_assembler_riscv.cpp +++ b/test/hotspot/gtest/riscv/test_assembler_riscv.cpp @@ -136,7 +136,7 @@ class CmpxchgTester { if (using_narrow()) { address entry = _masm.pc(); _masm.cmpxchg_narrow_value(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/c_rarg2, - ASMSIZE, Assembler::relaxed, Assembler::relaxed, + ASMSIZE, memory_order_relaxed, /*result*/ c_rarg3, boolean_result, c_rarg4, c_rarg5, c_rarg6); /* Uses also t0-t1, caller saved */ _masm.mv(c_rarg0, c_rarg3); _masm.ret(); @@ -145,28 +145,28 @@ class CmpxchgTester { switch(variant) { default: _masm.cmpxchg(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/c_rarg2, - ASMSIZE, Assembler::aq, Assembler::rl, + ASMSIZE, memory_order_seq_cst, /*result*/ c_rarg3, boolean_result); _masm.mv(c_rarg0, c_rarg3); break; case 1: // expected == result _masm.cmpxchg(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/c_rarg2, - ASMSIZE, Assembler::aq, Assembler::rl, + ASMSIZE, memory_order_seq_cst, /*result*/ c_rarg1, boolean_result); _masm.mv(c_rarg0, c_rarg1); break; case 2: // new_value == result _masm.cmpxchg(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/c_rarg2, - ASMSIZE, Assembler::aq, Assembler::rl, + ASMSIZE, memory_order_seq_cst, /*result*/ c_rarg2, boolean_result); _masm.mv(c_rarg0, c_rarg2); break; case 3: // expected == new_value _masm.cmpxchg(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/ c_rarg1, - ASMSIZE, Assembler::aq, Assembler::rl, + ASMSIZE, memory_order_seq_cst, /*result*/ c_rarg2, boolean_result); _masm.mv(c_rarg0, c_rarg2); break; @@ -581,7 +581,7 @@ class WeakCmpxchgTester { if (using_narrow()) { address entry = _masm.pc(); _masm.weak_cmpxchg_narrow_value(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/ c_rarg2, - ASMSIZE, Assembler::relaxed, Assembler::relaxed, + ASMSIZE, memory_order_relaxed, /*result*/ c_rarg3, c_rarg4, c_rarg5, c_rarg6); /* Uses also t0-t1, caller saved */ _masm.mv(c_rarg0, c_rarg3); _masm.ret(); @@ -589,7 +589,7 @@ class WeakCmpxchgTester { } else { address entry = _masm.pc(); _masm.weak_cmpxchg(/*addr*/ c_rarg0, /*expected*/ c_rarg1, /*new_value*/ c_rarg2, - ASMSIZE, Assembler::relaxed, Assembler::relaxed, /*result*/ c_rarg3); + ASMSIZE, memory_order_relaxed, /*result*/ c_rarg3); _masm.mv(c_rarg0, c_rarg3); _masm.ret(); _weak = ((weak_cmpxchg_func)entry); diff --git a/test/hotspot/jtreg/ProblemList-AotJdk.txt b/test/hotspot/jtreg/ProblemList-AotJdk.txt index bb5793cd4a3d..e772230bc315 100644 --- a/test/hotspot/jtreg/ProblemList-AotJdk.txt +++ b/test/hotspot/jtreg/ProblemList-AotJdk.txt @@ -53,10 +53,21 @@ compiler/intrinsics/klass/TestIsPrimitive.java 0000000 generic-all # However when AOTClassLinking is enabled, Integer is always resolved at JVM start-up. compiler/ciReplay/TestInliningProtectionDomain.java 0000000 generic-all +# The test is very sensetive to profiling date for String class and fail +# when use training data from AOT cache created from training with +# different Java application: TestSetupAOT.java +compiler/stringopts/TestStringConcatIR.java 0000000 generic-all + # These tests fail often with AotJdk due to JDK-8323727 compiler/arguments/TestStressReflectiveCode.java 8323727 generic-all compiler/arraycopy/TestCloneWithStressReflectiveCode.java 8323727 generic-all +serviceability/sa/TestJhsdbJstackMixedWithXComp.java#xcomp-disable-tiered-compilation 8382548 linux-aarch64 + +compiler/calls/NativeCalls.java 8383780 generic-all + +vmTestbase/vm/mlvm/indy/stress/jdi/breakpointInCompiledCode/Test.java 8383781 generic-all + ############################################################################# # Preview project specific failures go here at the end of the file. diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index ca79a093beaf..9fee7e62e0b5 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -69,10 +69,6 @@ compiler/c2/aarch64/TestStaticCallStub.java 8359963 generic-aarch64 compiler/escapeAnalysis/TestBCEscapeAnalyzerOverflow.java 8387392 windows-aarch64 -compiler/vectorapi/AllBitsSetVectorMatchRuleTest.java 8391806 generic-aarch64 - -compiler/vectorapi/VectorMaskCompareNotTest.java 8392087 windows-x64 - compiler/vectorapi/VectorExpressionFuzzer.java 8337281 linux-aarch64,macosx-aarch64 compiler/igvn/TestIncorrectDeadPathTypeNode.java 8392354 generic-all @@ -93,7 +89,6 @@ gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java#generational 83869 gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java#default 8386964 generic-all gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java#generational 8386964 generic-all gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java#default 8386964 generic-all -gc/metaspace/TestMetaspaceFirstGC.java 8392597 generic-all ############################################################################# diff --git a/test/hotspot/jtreg/TEST.ROOT b/test/hotspot/jtreg/TEST.ROOT index 6af0d4c97ce4..1057a40f3629 100644 --- a/test/hotspot/jtreg/TEST.ROOT +++ b/test/hotspot/jtreg/TEST.ROOT @@ -82,6 +82,7 @@ requires.properties= \ vm.cds.default.archive.available \ vm.cds.nocoops.archive.available \ vm.cds.nocoh.archive.available \ + vm.cds.nocoops.nocoh.archive.available \ vm.cds.custom.loaders \ vm.cds.supports.aot.class.linking \ vm.cds.supports.aot.code.caching \ diff --git a/test/hotspot/jtreg/TEST.groups b/test/hotspot/jtreg/TEST.groups index 7589a762343d..298f9590db91 100644 --- a/test/hotspot/jtreg/TEST.groups +++ b/test/hotspot/jtreg/TEST.groups @@ -556,10 +556,15 @@ tier1_runtime_appcds = \ runtime/cds/appcds/aotCache/HelloAOTCache.java \ runtime/cds/appcds/aotCode \ runtime/cds/appcds/HelloTest.java \ - -runtime/cds/appcds/aotCode/AOTCodeFlags.java + -runtime/cds/appcds/aotCode/AOTCodeFlags.java \ + -runtime/cds/appcds/aotCode/TestAOTCodeCounters.java \ + -runtime/cds/appcds/aotCode/TestAOTCodeFeatures.java tier1_runtime_appcds_exclude = \ runtime/cds/appcds/ \ + runtime/cds/appcds/aotCode/AOTCodeFlags.java \ + runtime/cds/appcds/aotCode/TestAOTCodeCounters.java \ + runtime/cds/appcds/aotCode/TestAOTCodeFeatures.java \ -:tier1_runtime_appcds tier1_runtime_no_cds = \ diff --git a/test/hotspot/jtreg/compiler/ccp/TestConcurrentClassLoadingDuringCCP.java b/test/hotspot/jtreg/compiler/ccp/TestConcurrentClassLoadingDuringCCP.java new file mode 100644 index 000000000000..c17835311219 --- /dev/null +++ b/test/hotspot/jtreg/compiler/ccp/TestConcurrentClassLoadingDuringCCP.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2026, 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 8393482 + * @summary Test bailout from PhaseCCP and compilation when CHA changed + * @requires vm.compiler2.enabled & vm.flagless & vm.bits == 64 & vm.debug == true + * @comment The test uses debug flag TracePhaseCCP to check for DecodeNKlass type + * @library /test/lib + * @modules java.base/jdk.internal.misc + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. + * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI + * -XX:+TracePhaseCCP -XX:+PrintCompilation + * -XX:+LogVMOutput -XX:LogFile=ccp_test.log + * -XX:CompileCommand=quiet + * -XX:CompileCommand=compileonly,${test.main.class}::test* + * -XX:CompileCommand=inline,${test.main.class}::inline* + * ${test.main.class} + */ + +package compiler.ccp; + +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import jdk.test.lib.Utils; +import jdk.test.whitebox.WhiteBox; + +/* + * The loader thread watches the VM log file until CCP prints the exact + * type for DecodeNKlass generated for array.clone(). At that point + * both, klass load and decode, nodes have cached the old exact type. + * The loader thread then loads Child subclass making the cached type + * of DecodeNKlass invalid. Without the fix, CCP verification asserts. + * With the fix, PrintCompilation reports that compilation was skipped + * because of concurrent class loading. + */ + +public class TestConcurrentClassLoadingDuringCCP { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + private static final String TEST_CLASS = TestConcurrentClassLoadingDuringCCP.class.getName(); + private static final String CHILD_CLASS = TEST_CLASS + "$Child"; + private static final Path LOG_FILE = Path.of("ccp_test.log"); + private static final long TIMEOUT_SEC = Utils.adjustTimeout(60); // 60 sec + + private static volatile Throwable failure; + + static class Parent {} + static class Child extends Parent {} + + public static void main(String[] args) throws Exception { + if (WB.isClassAlive(CHILD_CLASS)) { + throw new RuntimeException(CHILD_CLASS + " should not be loaded"); + } + Method testMethod = TestConcurrentClassLoadingDuringCCP.class + .getDeclaredMethod("test", Parent[][].class); + + CountDownLatch loaderReady = new CountDownLatch(1); + Thread loader = new Thread(() -> { + try { + // Unblock await() + loaderReady.countDown(); + // Wait TracePhaseCCP output + waitForLog(" DecodeNKlass === ", "$Parent:Constant"); + // Load subclass + Class.forName(CHILD_CLASS); + } catch (Throwable t) { + failure = t; + } + }, "loader"); + loader.start(); + + if (!loaderReady.await(TIMEOUT_SEC, TimeUnit.SECONDS)) { + throw new RuntimeException("Loader thread did not start"); + } + // Request C2 Tier4 compilation + if (!WB.enqueueMethodForCompilation(testMethod, 4)) { + throw new RuntimeException("Could not enqueue test method for C2 compilation"); + } + loader.join(TimeUnit.SECONDS.toMillis(TIMEOUT_SEC)); + if (loader.isAlive()) { + loader.interrupt(); + throw new RuntimeException("Timeout waiting for loader thread"); + } + if (failure != null) { + throw new RuntimeException(failure); + } + + waitForLog(TEST_CLASS + "::test", "COMPILE SKIPPED: concurrent class loading"); + if (WB.isMethodCompiled(testMethod)) { + throw new RuntimeException("Compilation should bail out"); + } + } + + private static void waitForLog(String... patterns) throws Exception { + long timeout = System.nanoTime() + TimeUnit.SECONDS.toNanos(TIMEOUT_SEC); + do { + String output = Files.readString(LOG_FILE); + if (output.lines().anyMatch(line -> containsAll(line, patterns))) { + return; // Found " DecodeNKlass === .* $Parent:Constant" + } + Thread.sleep(1); + } while (System.nanoTime() < timeout); + throw new RuntimeException("Did not find " + String.join("...", patterns) + + " in " + LOG_FILE); + } + + private static boolean containsAll(String line, String... patterns) { + for (String pattern : patterns) { + if (!line.contains(pattern)) { + return false; + } + } + return true; + } + + // When C2 parses the test() and inlined methods, Child has not been loaded, + // so C2 treats Parent as a leaf class. The klass type generated for `clone` + // thus contains exact Parent class. + // After CCP caches this type, the loader thread loads Child subclass. + // This invalidates the exact Parent and causes LoadNKlass type to widen + // while CCP is still running. + + // Use static variables to avoid folding of inlined methods. + private static volatile int result; + private static volatile int var; + + // Use 2-dims array to force C2 generate LoadNklass -> DecodeNKlass nodes. + static Parent[][] test(Parent[][] array) { + Parent[][] clone = array.clone(); + var = inline0(); + return clone; + } + + private static int inline0() { + return inline1() + inline1() + inline1() + inline1(); + } + + private static int inline1() { + return inline2() + inline2() + inline2() + inline2(); + } + + private static int inline2() { + return inline3() + inline3() + inline3() + inline3(); + } + + private static int inline3() { + return inline4() + inline4() + inline4() + inline4(); + } + + private static int inline4() { + return inline5() + inline5() + inline5() + inline5(); + } + + private static int inline5() { + return result; + } +} diff --git a/test/hotspot/jtreg/compiler/codegen/ShiftTest.java b/test/hotspot/jtreg/compiler/codegen/ShiftTest.java index 8d051c127c5a..6d430d584ceb 100644 --- a/test/hotspot/jtreg/compiler/codegen/ShiftTest.java +++ b/test/hotspot/jtreg/compiler/codegen/ShiftTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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 4093292 8280511 + * @bug 4093292 8280511 8394343 * @summary Test for correct code generation by the JIT * @library /test/lib * @run main compiler.codegen.ShiftTest @@ -171,6 +171,50 @@ private static long negSignedRightShiftLCorner(long input) { return -(input >> 66); } + private static int[] posInt = { + 0, 1, 2, 3, (1<<16) - 1, 1<<16, Integer.MAX_VALUE + }; + + private static long[] posInt_LeftShift20_expected = { + 0, 1048576, 2097152, 3145728, 68718428160L, 68719476736L, 2251799812636672L + }; + + private static long[] posInt_LeftShift31_expected = { + 0, 2147483648L, 4294967296L, 6442450944L, 140735340871680L, 140737488355328L, 4611686016279904256L + }; + + private static long[] posInt_LeftShift32_expected = { + 0, 4294967296L, 8589934592L, 12884901888L, 281470681743360L, 281474976710656L, 9223372032559808512L + }; + + private static long[] posInt_LeftShift33_expected = { + 0, 8589934592L, 17179869184L, 25769803776L, 562941363486720L, 562949953421312L, -8589934592L + }; + + private static long[] posInt_LeftShift63_expected = { + 0, -9223372036854775808L, 0, -9223372036854775808L, -9223372036854775808L, 0, -9223372036854775808L + }; + + private static long leftShiftPosI2L_20(int input) { + return (long)(input & Integer.MAX_VALUE) << 20; + } + + private static long leftShiftPosI2L_31(int input) { + return (long)(input & Integer.MAX_VALUE) << 31; + } + + private static long leftShiftPosI2L_32(int input) { + return (long)(input & Integer.MAX_VALUE) << 32; + } + + private static long leftShiftPosI2L_33(int input) { + return (long)(input & Integer.MAX_VALUE) << 33; + } + + private static long leftShiftPosI2L_63(int input) { + return (long)(input & Integer.MAX_VALUE) << 63; + } + private static void testNegShift() { for (int i = 0; i < 20_000; i++) { for (int j = 0; j < ispecial.length; j++) { @@ -189,6 +233,13 @@ private static void testNegShift() { Asserts.assertEquals(negUnsignedRightShiftLCorner(lspecial[j]), lspecial_UnsignedRightShiftCorner_expected[j]); Asserts.assertEquals(negSignedRightShiftLCorner(lspecial[j]), lspecial_SignedRightShiftCorner_expected[j]); } + for (int j = 0; j < posInt.length; j++) { + Asserts.assertEquals(leftShiftPosI2L_20(posInt[j]), posInt_LeftShift20_expected[j]); + Asserts.assertEquals(leftShiftPosI2L_31(posInt[j]), posInt_LeftShift31_expected[j]); + Asserts.assertEquals(leftShiftPosI2L_32(posInt[j]), posInt_LeftShift32_expected[j]); + Asserts.assertEquals(leftShiftPosI2L_33(posInt[j]), posInt_LeftShift33_expected[j]); + Asserts.assertEquals(leftShiftPosI2L_63(posInt[j]), posInt_LeftShift63_expected[j]); + } } } diff --git a/test/hotspot/jtreg/compiler/compilercontrol/commands/CompileLevelPrintTest.java b/test/hotspot/jtreg/compiler/compilercontrol/commands/CompileLevelPrintTest.java index 340c55ef99c3..1f4562defa53 100644 --- a/test/hotspot/jtreg/compiler/compilercontrol/commands/CompileLevelPrintTest.java +++ b/test/hotspot/jtreg/compiler/compilercontrol/commands/CompileLevelPrintTest.java @@ -165,12 +165,12 @@ static class Runner { private static final Pattern reCompileCommand = Pattern.compile( "CompileCommand: (.*)"); private static final Pattern reCompilation = Pattern.compile( - "(\\d+) (C1|C2|no compiler): *(\\d+) ([ %][ s][ !][ b][ n]) ([-0-4 ]) +([^ ]+).*"); + "(\\d+) (C1|C2|no compiler): *(\\d+) ([ %][ s][ !][ b][ n][ A][ P]) ([-0-4 ]) +([^ ]+).*"); private static final Pattern reExcludeCompile = Pattern.compile( ".*made not compilable on level (\\d) +([^ ]+) .* excluded by CompileCommand"); private static final Pattern reCompiledMethod = Pattern.compile( ".*-{35} Assembly -{35}\\n(?:\\[[0-9.]+s]\\[warning]\\[os] Loading hsdis library failed\\n)?\\nCompiled method \\((?:c1|c2)\\) (\\d+) ([Cc][12]): *" - + "(\\d+) ([ %][ s][ !][ b][ n]) ([-0-4 ]) +([^ ]+) +(@ -?[0-9]+ +)?\\(\\d+ bytes\\)", Pattern.DOTALL); + + "(\\d+) ([ %][ s][ !][ b][ n][ A][ P]) ([-0-4 ]) +([^ ]+) +(@ -?[0-9]+ +)?\\(\\d+ bytes\\)", Pattern.DOTALL); private static final Pattern reMethodData = Pattern.compile( ".*-{72}\\nstatic ([^\\n]+)\\n *interpreter_invocation_count: *\\d+\\n *invocation_counter: *\\d+", Pattern.DOTALL); private static final Pattern reEndOfLog = Pattern.compile(""); diff --git a/test/hotspot/jtreg/compiler/gallery/TestNormalMapping.java b/test/hotspot/jtreg/compiler/gallery/TestNormalMapping.java index 5c1338224856..968e017cbc85 100644 --- a/test/hotspot/jtreg/compiler/gallery/TestNormalMapping.java +++ b/test/hotspot/jtreg/compiler/gallery/TestNormalMapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 @@ -107,7 +107,7 @@ public void run() { IRNode.STORE_VECTOR, "> 0"}, applyIf = {"AlignVector", "false"}, applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) private void testIR() { // This call should inline givne the CompileCommand above. state.update(); diff --git a/test/hotspot/jtreg/compiler/gallery/TestParticleLife.java b/test/hotspot/jtreg/compiler/gallery/TestParticleLife.java index bb1eea927c78..ce2645dff282 100644 --- a/test/hotspot/jtreg/compiler/gallery/TestParticleLife.java +++ b/test/hotspot/jtreg/compiler/gallery/TestParticleLife.java @@ -101,7 +101,7 @@ public void run() { IRNode.STORE_VECTOR, "> 0"}, applyIf = {"AlignVector", "false"}, applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}) private void testIR_updatePositions() { // This call should inline given the CompileCommand above. // We expect auto vectorization of the relatively simple loop. @@ -129,7 +129,7 @@ private void testIR_updatePositions() { IRNode.STORE_VECTOR, "= 0", IRNode.ADD_REDUCTION_VF, "= 0"}, applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}) private void testIR_updateForcesScalar() { // This call should inline given the CompileCommand above. // We expect no vectorization, though it may in principle be possible @@ -156,7 +156,7 @@ private void testIR_updateForcesScalar() { IRNode.VECTOR_BLEND_F, "> 0", IRNode.ADD_REDUCTION_VF, "> 0"}, // instead we reduce the vector to a scalar applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeature = {"avx2", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "rvv", "true"}) private void testIR_updateForcesVectorAPI_Inner_Gather() { // This call should inline given the CompileCommand above. // We expect the VectorAPI calls to intrinsify. @@ -182,7 +182,7 @@ private void testIR_updateForcesVectorAPI_Inner_Gather() { IRNode.VECTOR_BLEND_F, "> 0", IRNode.ADD_REDUCTION_VF, "> 0"}, // instead we reduce the vector to a scalar applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true", "rvv", "true"}) private void testIR_updateForcesVectorAPI_Inner_Rearranged() { // This call should inline given the CompileCommand above. // We expect the VectorAPI calls to intrinsify. @@ -210,7 +210,7 @@ private void testIR_updateForcesVectorAPI_Inner_Rearranged() { IRNode.STORE_VECTOR, "> 0", // store back a vector IRNode.ADD_REDUCTION_VF, "= 0"}, // and no reduction operation applyIfPlatform = {"64-bit", "true"}, - applyIfCPUFeature = {"avx2", "true"}) + applyIfCPUFeatureOr = {"avx2", "true", "rvv", "true"}) private void testIR_updateForcesVectorAPI_Outer() { // This call should inline given the CompileCommand above. // We expect the VectorAPI calls to intrinsify. diff --git a/test/hotspot/jtreg/compiler/igvn/TestConvL2INodeIdeal.java b/test/hotspot/jtreg/compiler/igvn/TestConvL2INodeIdeal.java new file mode 100644 index 000000000000..9febd78fd045 --- /dev/null +++ b/test/hotspot/jtreg/compiler/igvn/TestConvL2INodeIdeal.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2026, 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.igvn; + +/* + * @test + * @bug 8392942 + * @summary Test that IGVN revisits ConvL2I when the mask input of an AndL becomes + * 0xFFFFFFFF in the ConvL2I(AndL(x, 0xFFFFFFFF)) pattern. + * @requires vm.compiler2.enabled + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions + * -Xbatch + * -XX:CompileCommand=compileonly,${test.main.class}::test + * -XX:VerifyIterativeGVN=1110 + * ${test.main.class} + * @run main ${test.main.class} + */ +public class TestConvL2INodeIdeal { + static int iFld; + + public static void main(String[] args) { + for (int i = 0; i < 10000; i++) { + test(); + } + } + + static void test() { + for (int i = 0; i < 2; i++) { + iFld = (int) (iFld & ((i - 5L) >>> 32)); + } + } +} diff --git a/test/hotspot/jtreg/compiler/inlining/LateInlinePrinting.java b/test/hotspot/jtreg/compiler/inlining/LateInlinePrinting.java index 88b483076e3f..0d1a284a4d43 100644 --- a/test/hotspot/jtreg/compiler/inlining/LateInlinePrinting.java +++ b/test/hotspot/jtreg/compiler/inlining/LateInlinePrinting.java @@ -84,19 +84,16 @@ public static void main(String[] args) throws Exception { OutputAnalyzer analyzer = new OutputAnalyzer(pb.start()); analyzer.shouldHaveExitValue(0); - analyzer.shouldContain(""" -compiler.inlining.LateInlinePrinting$TestLateInlining::test2 (7 bytes) - @ 0 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined1 (1 bytes) inline (hot) late inline succeeded - @ 3 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined2 (1 bytes) inline (hot) late inline succeeded - """); - analyzer.shouldContain(""" -compiler.inlining.LateInlinePrinting$TestLateInlining::test1 (13 bytes) - @ 0 compiler.inlining.LateInlinePrinting$TestLateInlining::test3 (1 bytes) inline (hot) late inline succeeded - @ 3 compiler.inlining.LateInlinePrinting$TestLateInlining::testFailInline (1 bytes) failed to inline: disallowed by CompileCommand - @ 6 compiler.inlining.LateInlinePrinting$TestLateInlining::testFailInline (1 bytes) failed to inline: disallowed by CompileCommand - @ 9 compiler.inlining.LateInlinePrinting$TestLateInlining::test2 (7 bytes) inline (hot) late inline succeeded - @ 0 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined1 (1 bytes) inline (hot) late inline succeeded - @ 3 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined2 (1 bytes) inline (hot) late inline succeeded - """); + analyzer.shouldContain("compiler.inlining.LateInlinePrinting$TestLateInlining::test2 (7 bytes)"); + analyzer.shouldContain("@ 0 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined1 (1 bytes) inline (hot) late inline succeeded"); + analyzer.shouldContain("@ 3 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined2 (1 bytes) inline (hot) late inline succeeded"); + + analyzer.shouldContain("compiler.inlining.LateInlinePrinting$TestLateInlining::test1 (13 bytes)"); + analyzer.shouldContain("@ 0 compiler.inlining.LateInlinePrinting$TestLateInlining::test3 (1 bytes) inline (hot) late inline succeeded"); + analyzer.shouldContain("@ 3 compiler.inlining.LateInlinePrinting$TestLateInlining::testFailInline (1 bytes) failed to inline: disallowed by CompileCommand"); + analyzer.shouldContain("@ 6 compiler.inlining.LateInlinePrinting$TestLateInlining::testFailInline (1 bytes) failed to inline: disallowed by CompileCommand"); + analyzer.shouldContain("@ 9 compiler.inlining.LateInlinePrinting$TestLateInlining::test2 (7 bytes) inline (hot) late inline succeeded"); + analyzer.shouldContain("@ 0 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined1 (1 bytes) inline (hot) late inline succeeded"); + analyzer.shouldContain("@ 3 compiler.inlining.LateInlinePrinting$TestLateInlining::inlined2 (1 bytes) inline (hot) late inline succeeded"); } } diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 9c11f56003b7..87ad9f029f7c 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -2497,6 +2497,16 @@ public static void anyStoreOfNodes(String irNodePlaceholder, String fieldHolder) machOnlyNameRegex(RISCV_VAND_NOTL_VX_MASKED, "vand_notL_vx_masked"); } + public static final String RISCV_VCOMPRESS_BITS_MASKED = PREFIX + "RISCV_VCOMPRESS_BITS_MASKED" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VCOMPRESS_BITS_MASKED, "vcompressBits_masked"); + } + + public static final String RISCV_VEXPAND_BITS_MASKED = PREFIX + "RISCV_VEXPAND_BITS_MASKED" + POSTFIX; + static { + machOnlyNameRegex(RISCV_VEXPAND_BITS_MASKED, "vexpandBits_masked"); + } + public static final String VECTOR_SLICE_B = VECTOR_PREFIX + "VECTOR_SLICE_B" + POSTFIX; static { vectorNode(VECTOR_SLICE_B, "VectorSlice", TYPE_BYTE); diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java index 6fe4b31b9ef0..1b74232a81f3 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/TestFramework.java @@ -146,6 +146,7 @@ public class TestFramework { "LogCompilation", "UseCompactObjectHeaders", "UseFMA", + "AOTCache", // Riscv "UseRVV", "UseZbb", diff --git a/test/hotspot/jtreg/compiler/loopopts/TestRemoveStoresAfterPeeling.java b/test/hotspot/jtreg/compiler/loopopts/TestRemoveStoresAfterPeeling.java new file mode 100644 index 000000000000..0a3c69ca4643 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestRemoveStoresAfterPeeling.java @@ -0,0 +1,261 @@ +/* + * Copyright (c) 2026, 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.loopopts; + +import compiler.lib.ir_framework.*; +import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; + +/* + * @test + * @bug 8380089 + * @summary Test that stores can be elided by peeling the loop. + * @library /test/lib / + * @run driver ${test.main.class} + */ +public class TestRemoveStoresAfterPeeling { + private static class A { + int v; + } + + public static void main(String[] args) { + var framework = new TestFramework(); + framework.addScenarios(new Scenario(0)); + if (Platform.isDebugBuild()) { + // When a store is not removed from a loop after that loop is peeled, there will be + // multiple stores in the graph + framework.addScenarios(new Scenario(1, "-XX:+StressLoopPeeling")); + } + framework.start(); + } + + @Test + @IR(counts = {IRNode.STORE_I, "1"}) + private void testStoreHoisting(A a, int v) { + for (int i = 1; i < 100; i *= 2) { + // Simple case, the store can be hoisted above the loop + a.v = v; + } + } + + @Run(test = "testStoreHoisting") + public void runStoreHoisting() { + A a = new A(); + testStoreHoisting(a, 1); + Asserts.assertEQ(1, a.v); + } + + @Test + @IR(counts = {IRNode.STORE_I, "1"}) + private void testStorePeeling1(int limit, A a, int v) { + for (int i = 1; i < 100; i *= 2) { + // The store does not post-dominate the loop head, so it cannot be hoisted + if (i >= limit) { + break; + } + + a.v = v; + } + } + + @Run(test = "testStorePeeling1") + public void runStorePeeling1() { + A a = new A(); + testStorePeeling1(0, a, 1); + Asserts.assertEQ(0, a.v); + testStorePeeling1(200, a, 1); + Asserts.assertEQ(1, a.v); + } + + @Test + @IR(counts = {IRNode.STORE_I, "1"}, phase = CompilePhase.BEFORE_MACRO_EXPANSION) + private A testStorePeeling2(A a1, int v1, float v2) { + A a2 = new A(); + for (int i = 1; i < 100; i *= 2) { + // There are 2 independent stores in the loop + a2.v = Float.floatToRawIntBits(i * v2); + a1.v = v1; + } + return a2; + } + + @Run(test = "testStorePeeling2") + public void runStorePeeling2() { + A a1 = new A(); + A a2 = testStorePeeling2(a1, 1, 1); + Asserts.assertEQ(1, a1.v); + Asserts.assertEQ(Float.floatToRawIntBits(64), a2.v); + } + + @Test + @IR(counts = {IRNode.STORE_I, "1"}, phase = CompilePhase.BEFORE_MACRO_EXPANSION) + private A testStorePeeling3(int limit, A a1, int v1, float v2) { + A a2 = new A(); + for (int i = 1; i < 100; i *= 2) { + // Combine the previous 2 cases + a2.v = Float.floatToRawIntBits(i * v2); + if (i >= limit) { + break; + } + a1.v = v1; + } + return a2; + } + + @Run(test = "testStorePeeling3") + public void runStorePeeling3() { + A a1 = new A(); + A a2 = testStorePeeling3(0, a1, 1, 1); + Asserts.assertEQ(0, a1.v); + Asserts.assertEQ(Float.floatToRawIntBits(1), a2.v); + a2 = testStorePeeling3(200, a1, 1, 1); + Asserts.assertEQ(1, a1.v); + Asserts.assertEQ(Float.floatToRawIntBits(64), a2.v); + } + + @Test + @IR(counts = {IRNode.STORE_I, "1"}) + private int testStorePeeling4(A[] array, A a, int v) { + int sum = 0; + for (int i = 1; i < 100; i *= 2) { + // The store to a.v cannot be directly hoisted because the preceding load array[i].v + // may alias it. Peeling preserves the first iteration load-before-store ordering. + // Later identical stores are redundant. + sum += array[i].v; + a.v = v; + } + return sum; + } + + @Run(test = "testStorePeeling4") + public void runStorePeeling4() { + A[] array = new A[100]; + for (int i = 0; i < 100; i++) { + array[i] = new A(); + } + + A unrelated = new A(); + Asserts.assertEQ(0, testStorePeeling4(array, unrelated, 1)); + Asserts.assertEQ(1, testStorePeeling4(array, array[2], 1)); + array[2].v = 0; + Asserts.assertEQ(0, testStorePeeling4(array, array[1], 1)); + } + + @Test + @IR(counts = {IRNode.STORE_I, "1"}) + private int testStorePeeling5(boolean b, A[] array, A a, int v) { + int sum = 0; + for (int i = 1; i < 100; i *= 2) { + // Similar to testStorePeeling4, and this test triggers peeling without + // StressLoopPeeling + if (b) { + break; + } + + sum += array[i].v; + a.v = v; + } + return sum; + } + + @Run(test = "testStorePeeling5") + private void runStorePeeling5() { + A[] array = new A[100]; + for (int i = 0; i < 100; i++) { + array[i] = new A(); + } + Asserts.assertEQ(0, testStorePeeling5(true, array, array[2], 1)); + + A unrelated = new A(); + Asserts.assertEQ(0, testStorePeeling5(true, array, unrelated, 1)); + Asserts.assertEQ(0, testStorePeeling5(false, array, unrelated, 1)); + Asserts.assertEQ(1, testStorePeeling5(false, array, array[2], 1)); + array[2].v = 0; + Asserts.assertEQ(0, testStorePeeling5(false, array, array[1], 1)); + } + + @Test + private void testStoreNotElided1(int limit, A a, int v) { + for (int i = 1; i < 100; i *= 2) { + // Cannot elide the store after peeling because it does not dominate the back edge + if (i >= limit) { + a.v = v; + } + } + } + + @Run(test = "testStoreNotElided1") + public void runStoreNotElided1() { + A a = new A(); + testStoreNotElided1(-1, a, 1); + Asserts.assertEQ(1, a.v); + a.v = 0; + testStoreNotElided1(50, a, 1); + Asserts.assertEQ(1, a.v); + a.v = 0; + testStoreNotElided1(200, a, 1); + Asserts.assertEQ(0, a.v); + } + + @Test + private void testStoreNotElided2(A a1, A a2, int v1, int v2) { + for (int i = 1; i < 100; i *= 2) { + // Cannot elide the store after peeling because there is an interfering store + a2.v = Float.floatToRawIntBits(i * v2); + a1.v = v1; + } + } + + @Run(test = "testStoreNotElided2") + public void runStoreNotElided2() { + A a1 = new A(); + A a2 = new A(); + testStoreNotElided2(a1, a2, 1, 1); + Asserts.assertEQ(1, a1.v); + Asserts.assertEQ(Float.floatToRawIntBits(64), a2.v); + a1.v = 0; + testStoreNotElided2(a1, a1, 1, 1); + Asserts.assertEQ(1, a1.v); + } + + @Test + @IR(counts = {IRNode.STORE_I, "2"}, phase = CompilePhase.AFTER_PRE_MAIN_POST) + private int testPreMainPost(int[] array1, int[] array2, int v) { + int sum = 0; + for (int i = 0; i < array1.length; i++) { + // Iteration split also removes the store from the main-loop. It does not elide the + // store in the post-loop, though. + sum += array1[i]; + array2[1] = v; + } + return sum; + } + + @Run(test = "testPreMainPost") + public void runPreMainPost() { + int[] array1 = new int[100]; + int[] array2 = new int[100]; + Asserts.assertEQ(0, testPreMainPost(array1, array2, 1)); + Asserts.assertEQ(1, testPreMainPost(array1, array1, 1)); + } +} diff --git a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java index 297c03120697..f525c14694bd 100644 --- a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java +++ b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass/Launcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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,6 +29,8 @@ * java.instrument * @requires vm.jvmti & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @requires vm.compMode != "Xcomp" + * @comment Can't use AOT cache because -XX:TypeProfileLevel=222 invalidates training data + * @requires !vm.cds.supports.aot.code.caching | vm.opt.AOTCache == null * @build compiler.profiling.spectrapredefineclass.Agent * @run driver jdk.test.lib.helpers.ClassFileInstaller compiler.profiling.spectrapredefineclass.Agent * @run driver compiler.profiling.spectrapredefineclass.Launcher diff --git a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java index e7f5736889cb..ee77e86e3ba4 100644 --- a/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java +++ b/test/hotspot/jtreg/compiler/profiling/spectrapredefineclass_classloaders/Launcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, 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,6 +29,8 @@ * java.instrument * @requires vm.jvmti & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) * @requires vm.compMode != "Xcomp" + * @comment Can't use AOT cache because -XX:TypeProfileLevel=222 invalidates training data + * @requires !vm.cds.supports.aot.code.caching | vm.opt.AOTCache == null * @build compiler.profiling.spectrapredefineclass_classloaders.Agent * compiler.profiling.spectrapredefineclass_classloaders.Test * compiler.profiling.spectrapredefineclass_classloaders.A diff --git a/test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java b/test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java index ecd8f58c5ed8..126bd79f5af1 100644 --- a/test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java +++ b/test/hotspot/jtreg/compiler/runtime/safepoints/TestMachTempsAcrossSafepoints.java @@ -34,6 +34,8 @@ * @key randomness * @library /test/lib / * @requires vm.gc.G1 & vm.bits == 64 & vm.opt.final.UseCompressedOops == true + * @comment Can't use AOT cache because training data may affect shape of test's code + * @requires !vm.cds.supports.aot.code.caching | vm.opt.AOTCache == null * @run driver compiler.runtime.safepoints.TestMachTempsAcrossSafepoints */ diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestInvalidSpeculativeType.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestInvalidSpeculativeType.java new file mode 100644 index 000000000000..90ab8d69061b --- /dev/null +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestInvalidSpeculativeType.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2026, 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.valhalla.valuetypes; + +import jdk.internal.misc.Unsafe; +import jdk.internal.value.ValueClass; + +/* + * @test + * @bug 8393580 + * @summary For a Type, the speculative part should be a subset of the static part. + * @enablePreview + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.value + * @run main ${test.main.class} + * @run main/othervm -Xbatch -XX:-TieredCompilation + * -XX:+IgnoreUnrecognizedVMOptions -XX:+StressReflectiveCode + * -XX:TypeProfileLevel=222 -XX:PerMethodTrapLimit=0 + * -XX:CompileOnly=${test.main.class}::test + * ${test.main.class} + */ +public class TestInvalidSpeculativeType { + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + private static final Integer[] ARRAY = new Integer[4]; + + public static void main(String[] args) { + for (int i = 0; i < 20000; i++) { + test(ARRAY); + } + } + + private static boolean test(Integer[] array) { + if (!ValueClass.isFlatArray(array)) { + Integer _ = (Integer) UNSAFE.getReference(array, Unsafe.ARRAY_OBJECT_BASE_OFFSET); + return array instanceof Number[]; + } else { + return false; + } + } +} diff --git a/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullRestrictedArrayEscapeState.java b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullRestrictedArrayEscapeState.java new file mode 100644 index 000000000000..9a2326eb98d1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestNullRestrictedArrayEscapeState.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2026, 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.valhalla.valuetypes; + +import compiler.lib.ir_framework.*; +import jdk.internal.value.ValueClass; + +/** + * @test + * @bug 8392838 + * @summary Test that C2 propagates the correct escape state from + * null-restricted array allocations to their initialization values. + * @library /test/lib / + * @enablePreview + * @modules java.base/jdk.internal.value + * @run driver ${test.main.class} + */ + +class TestNullRestrictedArrayEscapeState { + + public static void main(String[] args) { + Scenario defaultLayout = + new Scenario(0); + Scenario referenceLayout = + new Scenario(1, "-XX:-UseArrayFlattening"); + Scenario nonAtomicFlatLayout = + new Scenario(2, "-XX:+UseArrayFlattening", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UseNullFreeNonAtomicValueFlattening"); + Scenario atomicFlatLayout + = new Scenario(3, "-XX:+UseArrayFlattening", + "-XX:+UnlockExperimentalVMOptions", + "-XX:-UseNullFreeNonAtomicValueFlattening", + "-XX:+UseNullFreeAtomicValueFlattening"); + TestFramework testFramework = new TestFramework(); + testFramework + .addFlags("--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED", + "--enable-preview") + .addScenarios(defaultLayout, referenceLayout, nonAtomicFlatLayout, atomicFlatLayout); + testFramework.start(); + } + + static class IdentityObject { + int val; + } + + static value class ValueHolder { + IdentityObject obj; + ValueHolder(IdentityObject obj) { + this.obj = obj; + } + } + + static ValueHolder globalHolder = null; + static ValueHolder[] globalHolders = null; + + @ForceInline + static ValueHolder createValueHolderWithSynchronizedFieldWrite() { + IdentityObject obj = new IdentityObject(); + ValueHolder holder = new ValueHolder(obj); + synchronized (obj) { + obj.val = 42; + } + return holder; + } + + @DontInline + static void escapeFirstHolder(ValueHolder[] holders) { + globalHolder = holders[0]; + } + + @DontInline + static void dontUse(ValueHolder[] holders) {} + + // Allocate a null-restricted atomic array, initialize it with a holder that + // references an identity object, and make it escape globally. C2 should + // propagate the array's global escape state to the referenced identity + // object, and preserve the synchronization operations. + @Test + @IR(counts = {IRNode.FAST_LOCK, "> 0", IRNode.FAST_UNLOCK, "> 0"}) + static void testAllocateEscapingNullRestrictedAtomicArray() { + ValueHolder holder = createValueHolderWithSynchronizedFieldWrite(); + ValueHolder[] holders = + (ValueHolder[])ValueClass.newNullRestrictedAtomicArray(ValueHolder.class, 1, holder); + globalHolders = holders; + } + + // Variant of the above test using a null-restricted non-atomic array. + @Test + @IR(counts = {IRNode.FAST_LOCK, "> 0", IRNode.FAST_UNLOCK, "> 0"}) + static void testAllocateEscapingNullRestrictedNonAtomicArray() { + ValueHolder holder = createValueHolderWithSynchronizedFieldWrite(); + ValueHolder[] holders = + (ValueHolder[])ValueClass.newNullRestrictedNonAtomicArray(ValueHolder.class, 1, holder); + globalHolders = holders; + } + + // Variant of the above test where the holder, rather than the array itself, + // escapes within a non-inlined call. C2 should propagate the global escape + // state of the array's fields to the referenced identity object, and + // preserve the synchronization operations. + @Test + @IR(counts = {IRNode.FAST_LOCK, "> 0", IRNode.FAST_UNLOCK, "> 0"}) + static void testAllocateNullRestrictedAtomicArrayWithEscapingElements() { + ValueHolder holder = createValueHolderWithSynchronizedFieldWrite(); + ValueHolder[] holders = + (ValueHolder[])ValueClass.newNullRestrictedAtomicArray(ValueHolder.class, 1, holder); + escapeFirstHolder(holders); + } + + // Allocate a null-restricted atomic array and initialize it with a holder + // that references an identity object. Since the non-inlined call does not + // access the array at all, C2 should classify the identity object as not + // globally escaping and optimize away the synchronization operations. + @Test + @IR(failOn = {IRNode.FAST_LOCK, IRNode.FAST_UNLOCK}) + static void testAllocateNullRestrictedAtomicArrayWithNonEscapingElements() { + ValueHolder holder = createValueHolderWithSynchronizedFieldWrite(); + ValueHolder[] holders = + (ValueHolder[])ValueClass.newNullRestrictedAtomicArray(ValueHolder.class, 1, holder); + dontUse(holders); + } +} diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java index ddf16ce185fc..6ba4b16bfb69 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorAddMulReduction.java @@ -37,7 +37,7 @@ /** * @test - * @bug 8320725 + * @bug 8320725 8391945 * @key randomness * @library /test/lib / * @summary Verify non-strictly ordered AddReductionVF/VD and MulReductionVF/VD @@ -170,7 +170,7 @@ public static void testFloatMulKernel(VectorSpecies SPECIES, float[] f) { @Test @IR(counts = {IRNode.MUL_REDUCTION_VF, ">=1", "no_strict_order", ">=1"}, failOn = {"requires_strict_order"}, - applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=8"}, phase = CompilePhase.PRINT_IDEAL) public static void testFloatMul_64() { @@ -180,7 +180,7 @@ public static void testFloatMul_64() { @Test @IR(counts = {IRNode.MUL_REDUCTION_VF, ">=1", "no_strict_order", ">=1"}, failOn = {"requires_strict_order"}, - applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=16"}, phase = CompilePhase.PRINT_IDEAL) public static void testFloatMul_128() { @@ -199,7 +199,7 @@ public static void testDoubleMulKernel(VectorSpecies SPECIES, double[] d) { @Test @IR(counts = {IRNode.MUL_REDUCTION_VD, ">=1", "no_strict_order", ">=1"}, failOn = {"requires_strict_order"}, - applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true"}, + applyIfCPUFeatureOr = {"asimd", "true", "sse2", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=16"}, phase = CompilePhase.PRINT_IDEAL) public static void testDoubleMul_128() { diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java b/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java index 8889ccd0d268..729b549218c9 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestVectorCompressExpandBits.java @@ -1,4 +1,5 @@ /* + * Copyright (c) 2026, Alibaba Group Holding Limited. All Rights Reserved. * Copyright (c) 2023, Arm Limited. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -29,19 +30,22 @@ import jdk.incubator.vector.IntVector; import jdk.incubator.vector.LongVector; +import jdk.incubator.vector.VectorMask; import jdk.incubator.vector.VectorOperators; import jdk.incubator.vector.VectorSpecies; import jdk.test.lib.Asserts; +import jdk.test.lib.Platform; import jdk.test.lib.Utils; /** * @test - * @bug 8301012 + * @bug 8301012 8391921 * @key randomness * @library /test/lib / - * @requires os.arch == "aarch64" & vm.cpu.features ~= ".*sve2.*" & vm.cpu.features ~= ".*svebitperm.*" - * @summary [vectorapi]: Intrinsify CompressBitsV/ExpandBitsV and add the AArch64 SVE backend implementation + * @requires (os.arch == "aarch64" & vm.cpu.features ~= ".*sve2.*" & vm.cpu.features ~= ".*svebitperm.*") | + * (os.arch == "riscv64" & vm.cpu.features ~= ".*rvv.*") + * @summary [vectorapi]: Test intrinsification of CompressBitsV/ExpandBitsV * @modules jdk.incubator.vector * @run driver compiler.vectorapi.TestVectorCompressExpandBits */ @@ -59,6 +63,7 @@ public class TestVectorCompressExpandBits { private static long[] la; private static long[] lb; private static long[] lr; + private static boolean[] laneMask; static { ia = new int[LENGTH]; @@ -67,16 +72,18 @@ public class TestVectorCompressExpandBits { la = new long[LENGTH]; lb = new long[LENGTH]; lr = new long[LENGTH]; + laneMask = new boolean[LENGTH]; for (int i = 0; i < LENGTH; i++) { ia[i] = RD.nextInt(25); ib[i] = RD.nextInt(25); la[i] = RD.nextLong(25); lb[i] = RD.nextLong(25); + laneMask[i] = RD.nextBoolean(); } } - // Test for vectorized Integer.compress operation in SVE2 + // Test for vectorized Integer.compress operation @Test @IR(counts = {IRNode.COMPRESS_BITS_VI, "> 0"}) public static void testIntCompress() { @@ -95,7 +102,28 @@ public static void testIntCompress_runner() { } } - // Test for vectorized Integer.expand operation in SVE2 + @Test + @IR(counts = {IRNode.COMPRESS_BITS_VI, "> 0"}) + @IR(counts = {IRNode.RISCV_VCOMPRESS_BITS_MASKED, "> 0"}, applyIfPlatform = {"riscv64", "true"}) + public static void testIntCompressMasked() { + for (int i = 0; i < LENGTH; i += I_SPECIES.length()) { + IntVector av = IntVector.fromArray(I_SPECIES, ia, i); + IntVector bv = IntVector.fromArray(I_SPECIES, ib, i); + VectorMask vm = VectorMask.fromArray(I_SPECIES, laneMask, i); + av.lanewise(VectorOperators.COMPRESS_BITS, bv, vm).intoArray(ir, i); + } + } + + @Run(test = "testIntCompressMasked") + public static void testIntCompressMasked_runner() { + testIntCompressMasked(); + for (int i = 0; i < LENGTH; i++) { + int expected = laneMask[i] ? Integer.compress(ia[i], ib[i]) : ia[i]; + Asserts.assertEquals(expected, ir[i]); + } + } + + // Test for vectorized Integer.expand operation @Test @IR(counts = {IRNode.EXPAND_BITS_VI, "> 0"}) public static void testIntExpand() { @@ -114,7 +142,28 @@ public static void testIntExpand_runner() { } } - // Test for vectorized Long.compress operation in SVE2 + @Test + @IR(counts = {IRNode.EXPAND_BITS_VI, "> 0"}) + @IR(counts = {IRNode.RISCV_VEXPAND_BITS_MASKED, "> 0"}, applyIfPlatform = {"riscv64", "true"}) + public static void testIntExpandMasked() { + for (int i = 0; i < LENGTH; i += I_SPECIES.length()) { + IntVector av = IntVector.fromArray(I_SPECIES, ia, i); + IntVector bv = IntVector.fromArray(I_SPECIES, ib, i); + VectorMask vm = VectorMask.fromArray(I_SPECIES, laneMask, i); + av.lanewise(VectorOperators.EXPAND_BITS, bv, vm).intoArray(ir, i); + } + } + + @Run(test = "testIntExpandMasked") + public static void testIntExpandMasked_runner() { + testIntExpandMasked(); + for (int i = 0; i < LENGTH; i++) { + int expected = laneMask[i] ? Integer.expand(ia[i], ib[i]) : ia[i]; + Asserts.assertEquals(expected, ir[i]); + } + } + + // Test for vectorized Long.compress operation @Test @IR(counts = {IRNode.COMPRESS_BITS_VL, "> 0"}) public static void testLongCompress() { @@ -133,7 +182,28 @@ public static void testLongCompress_runner() { } } - // Test for vectorized Long.expand operation in SVE2 + @Test + @IR(counts = {IRNode.COMPRESS_BITS_VL, "> 0"}) + @IR(counts = {IRNode.RISCV_VCOMPRESS_BITS_MASKED, "> 0"}, applyIfPlatform = {"riscv64", "true"}) + public static void testLongCompressMasked() { + for (int i = 0; i < LENGTH; i += L_SPECIES.length()) { + LongVector av = LongVector.fromArray(L_SPECIES, la, i); + LongVector bv = LongVector.fromArray(L_SPECIES, lb, i); + VectorMask vm = VectorMask.fromArray(L_SPECIES, laneMask, i); + av.lanewise(VectorOperators.COMPRESS_BITS, bv, vm).intoArray(lr, i); + } + } + + @Run(test = "testLongCompressMasked") + public static void testLongCompressMasked_runner() { + testLongCompressMasked(); + for (int i = 0; i < LENGTH; i++) { + long expected = laneMask[i] ? Long.compress(la[i], lb[i]) : la[i]; + Asserts.assertEquals(expected, lr[i]); + } + } + + // Test for vectorized Long.expand operation @Test @IR(counts = {IRNode.EXPAND_BITS_VL, "> 0"}) public static void testLongExpand() { @@ -152,8 +222,33 @@ public static void testLongExpand_runner() { } } + @Test + @IR(counts = {IRNode.EXPAND_BITS_VL, "> 0"}) + @IR(counts = {IRNode.RISCV_VEXPAND_BITS_MASKED, "> 0"}, applyIfPlatform = {"riscv64", "true"}) + public static void testLongExpandMasked() { + for (int i = 0; i < LENGTH; i += L_SPECIES.length()) { + LongVector av = LongVector.fromArray(L_SPECIES, la, i); + LongVector bv = LongVector.fromArray(L_SPECIES, lb, i); + VectorMask vm = VectorMask.fromArray(L_SPECIES, laneMask, i); + av.lanewise(VectorOperators.EXPAND_BITS, bv, vm).intoArray(lr, i); + } + } + + @Run(test = "testLongExpandMasked") + public static void testLongExpandMasked_runner() { + testLongExpandMasked(); + for (int i = 0; i < LENGTH; i++) { + long expected = laneMask[i] ? Long.expand(la[i], lb[i]) : la[i]; + Asserts.assertEquals(expected, lr[i]); + } + } + public static void main(String[] args) { - TestFramework.runWithFlags("--add-modules=jdk.incubator.vector", - "-XX:UseSVE=2"); + TestFramework testFramework = new TestFramework(); + testFramework.addFlags("--add-modules=jdk.incubator.vector"); + if (Platform.isAArch64()) { + testFramework.addFlags("-XX:UseSVE=2"); + } + testFramework.start(); } } diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java index 3d939ccdd224..26e159fb768d 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorCompareWithZeroTest.java @@ -159,8 +159,7 @@ private static void assertArrayEquals(double[] a, boolean[] r, DoubleOp f) { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }, - applyIf = { "TieredCompilation", "true" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }) public static void testByteVectorEqualToZero() { ByteVector av = ByteVector.fromArray(B_SPECIES, ba, 0); av.compare(VectorOperators.EQ, 0).intoArray(br, 0); @@ -173,8 +172,7 @@ public static void testByteVectorEqualToZero_runner() { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }, - applyIf = { "TieredCompilation", "true" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }) public static void testShortVectorNotEqualToZero() { ShortVector av = ShortVector.fromArray(S_SPECIES, sa, 0); av.compare(VectorOperators.NE, 0).intoArray(sr, 0); @@ -187,8 +185,7 @@ public static void testShortVectorNotEqualToZero_runner() { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }, - applyIf = { "TieredCompilation", "true" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_I_NEON, ">= 1" }) public static void testIntVectorGreaterEqualToZero() { IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); av.compare(VectorOperators.GE, 0).intoArray(ir, 0); @@ -201,8 +198,7 @@ public static void testIntVectorGreaterEqualToZero_runner() { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_L_NEON, ">= 1" }, - applyIf = { "TieredCompilation", "true" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_L_NEON, ">= 1" }) public static void testLongVectorGreaterThanZero() { LongVector av = LongVector.fromArray(L_SPECIES, la, 0); av.compare(VectorOperators.GT, 0).intoArray(lr, 0); @@ -215,8 +211,7 @@ public static void testLongVectorGreaterThanZero_runner() { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_F_NEON, ">= 1" }, - applyIf = { "TieredCompilation", "true" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_F_NEON, ">= 1" }) public static void testFloatVectorLessEqualToZero() { FloatVector av = FloatVector.fromArray(F_SPECIES, fa, 0); av.compare(VectorOperators.LE, 0).intoArray(fr, 0); @@ -229,8 +224,7 @@ public static void testFloatVectorLessEqualToZero_runner() { } @Test - @IR(counts = { IRNode.VMASK_CMP_ZERO_D_NEON, ">= 1" }, - applyIf = { "TieredCompilation", "true" }) + @IR(counts = { IRNode.VMASK_CMP_ZERO_D_NEON, ">= 1" }) public static void testDoubleVectorLessThanZero() { DoubleVector av = DoubleVector.fromArray(D_SPECIES, da, 0); av.compare(VectorOperators.LT, 0).intoArray(dr, 0); @@ -243,31 +237,20 @@ public static void testDoubleVectorLessThanZero_runner() { } @Test - @IR(failOn = { IRNode.VMASK_CMP_ZERO_I_NEON }, - applyIf = { "TieredCompilation", "true" }) + @IR(failOn = { IRNode.VMASK_CMP_ZERO_I_NEON }) public static void testIntVectorUnsignedCondition() { IntVector av = IntVector.fromArray(I_SPECIES, ia, 0); av.compare(VectorOperators.UGT, 0).intoArray(ir, 0); } @Test - @IR(failOn = { IRNode.VMASK_CMP_ZERO_L_NEON }, - applyIf = { "TieredCompilation", "true" }) + @IR(failOn = { IRNode.VMASK_CMP_ZERO_L_NEON }) public static void testLongVectorUnsignedCondition() { LongVector av = LongVector.fromArray(L_SPECIES, la, 0); av.compare(VectorOperators.UGE, 0).intoArray(lr, 0); } public static void main(String[] args) { - // The @IR rules in this test verify that the optimized NEON compare-with-zero - // instructions (vmaskcmp_zero*_neon) are generated. IncrementalInlineVector is - // enabled by default; when a vector intrinsic fails to intrinsify, inlining its - // fallback implementation enlarges the compilation unit and, under unstable profiling, - // may prevent AbstractMask::intoArray() from being inlined. When intoArray() is not - // inlined, the mask is boxed before the call, which breaks the compare-with-zero - // match so the expected vmaskcmp_zero*_neon nodes are not produced. This only happens - // under unstable profiling (which makes the intoArray inlining decision - // non-deterministic); under the default profiling the match is stable. TestFramework testFramework = new TestFramework(); testFramework.setDefaultWarmup(10000) .addFlags("--add-modules=jdk.incubator.vector") diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java index f895283160a1..a5da6a87cd72 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMaskCompareNotTest.java @@ -276,8 +276,7 @@ public static void testCompareMaskNotDouble(VectorSpecies vs, VectorOper @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareEQMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.EQ); @@ -289,8 +288,7 @@ public static void testCompareEQMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareNEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.NE); @@ -302,8 +300,7 @@ public static void testCompareNEMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareLTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.LT); @@ -315,8 +312,7 @@ public static void testCompareLTMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareGTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.GT); @@ -328,8 +324,7 @@ public static void testCompareGTMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareLEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.LE); @@ -341,8 +336,7 @@ public static void testCompareLEMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareGEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.GE); @@ -354,8 +348,7 @@ public static void testCompareGEMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareULTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.ULT); @@ -367,8 +360,7 @@ public static void testCompareULTMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareUGTMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.UGT); @@ -380,8 +372,7 @@ public static void testCompareUGTMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareULEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.ULE); @@ -393,8 +384,7 @@ public static void testCompareULEMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareUGEMaskNotByte() { testCompareMaskNotByte(B_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsByte(B_SPECIES, VectorOperators.UGE); @@ -407,8 +397,7 @@ public static void testCompareUGEMaskNotByte() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareEQMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.EQ); @@ -420,8 +409,7 @@ public static void testCompareEQMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareNEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.NE); @@ -433,8 +421,7 @@ public static void testCompareNEMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareLTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.LT); @@ -446,8 +433,7 @@ public static void testCompareLTMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareGTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.GT); @@ -459,8 +445,7 @@ public static void testCompareGTMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareLEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.LE); @@ -472,8 +457,7 @@ public static void testCompareLEMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareGEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.GE); @@ -485,8 +469,7 @@ public static void testCompareGEMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareULTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.ULT); @@ -498,8 +481,7 @@ public static void testCompareULTMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareUGTMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.UGT); @@ -511,8 +493,7 @@ public static void testCompareUGTMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareULEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.ULE); @@ -524,8 +505,7 @@ public static void testCompareULEMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareUGEMaskNotShort() { testCompareMaskNotShort(S_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsShort(S_SPECIES, VectorOperators.UGE); @@ -538,8 +518,7 @@ public static void testCompareUGEMaskNotShort() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareEQMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.EQ); @@ -551,8 +530,7 @@ public static void testCompareEQMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareNEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.NE); @@ -564,8 +542,7 @@ public static void testCompareNEMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareLTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.LT); @@ -577,8 +554,7 @@ public static void testCompareLTMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareGTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.GT); @@ -590,8 +566,7 @@ public static void testCompareGTMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareLEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.LE); @@ -603,8 +578,7 @@ public static void testCompareLEMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareGEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.GE); @@ -616,8 +590,7 @@ public static void testCompareGEMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareULTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.ULT); @@ -629,8 +602,7 @@ public static void testCompareULTMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareUGTMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.UGT); @@ -642,8 +614,7 @@ public static void testCompareUGTMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareULEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.ULE); @@ -655,8 +626,7 @@ public static void testCompareULEMaskNotInt() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareUGEMaskNotInt() { testCompareMaskNotInt(I_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsInt(I_SPECIES, VectorOperators.UGE); @@ -670,8 +640,7 @@ public static void testCompareUGEMaskNotInt() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareEQMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.EQ, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.EQ); @@ -687,8 +656,7 @@ public static void testCompareEQMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareNEMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.NE, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.NE); @@ -704,8 +672,7 @@ public static void testCompareNEMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareLTMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.LT, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.LT); @@ -721,8 +688,7 @@ public static void testCompareLTMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareGTMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.GT, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.GT); @@ -738,8 +704,7 @@ public static void testCompareGTMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareLEMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.LE, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.LE); @@ -755,8 +720,7 @@ public static void testCompareLEMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareGEMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.GE, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.GE); @@ -772,8 +736,7 @@ public static void testCompareGEMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareULTMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.ULT, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.ULT); @@ -789,8 +752,7 @@ public static void testCompareULTMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareUGTMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.UGT, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.UGT); @@ -806,8 +768,7 @@ public static void testCompareUGTMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareULEMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.ULE, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.ULE); @@ -823,8 +784,7 @@ public static void testCompareULEMaskNotLong() { IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CAST, "= 1", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareUGEMaskNotLong() { testCompareMaskNotLong(L_SPECIES, VectorOperators.UGE, (m) -> { return m.not(); }); verifyResultsLong(L_SPECIES, VectorOperators.UGE); @@ -839,8 +799,7 @@ public static void testCompareUGEMaskNotLong() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareEQMaskNotFloat() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fb, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fb); @@ -852,8 +811,7 @@ public static void testCompareEQMaskNotFloat() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareNEMaskNotFloat() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fb, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fb); @@ -865,8 +823,7 @@ public static void testCompareNEMaskNotFloat() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareEQMaskNotFloatNaN() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fnan, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fnan); @@ -878,8 +835,7 @@ public static void testCompareEQMaskNotFloatNaN() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareNEMaskNotFloatNaN() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fnan, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fnan); @@ -891,8 +847,7 @@ public static void testCompareNEMaskNotFloatNaN() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareEQMaskNotFloatPositiveInfinity() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fpinf, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fpinf); @@ -904,8 +859,7 @@ public static void testCompareEQMaskNotFloatPositiveInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareNEMaskNotFloatPositiveInfinity() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fpinf, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fpinf); @@ -917,8 +871,7 @@ public static void testCompareNEMaskNotFloatPositiveInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareEQMaskNotFloatNegativeInfinity() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fninf, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.EQ, fa, fninf); @@ -930,8 +883,7 @@ public static void testCompareEQMaskNotFloatNegativeInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }) public static void testCompareNEMaskNotFloatNegativeInfinity() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.NE, fa, fninf, (m) -> { return m.not(); }); verifyResultsFloat(F_SPECIES, VectorOperators.NE, fa, fninf); @@ -943,8 +895,7 @@ public static void testCompareNEMaskNotFloatNegativeInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareEQMaskNotDouble() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, db, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, db); @@ -956,8 +907,7 @@ public static void testCompareEQMaskNotDouble() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareNEMaskNotDouble() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, db, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, db); @@ -969,8 +919,7 @@ public static void testCompareNEMaskNotDouble() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareEQMaskNotDoubleNaN() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dnan, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dnan); @@ -982,8 +931,7 @@ public static void testCompareEQMaskNotDoubleNaN() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareNEMaskNotDoubleNaN() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dnan, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dnan); @@ -995,8 +943,7 @@ public static void testCompareNEMaskNotDoubleNaN() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareEQMaskNotDoublePositiveInfinity() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dpinf, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dpinf); @@ -1008,8 +955,7 @@ public static void testCompareEQMaskNotDoublePositiveInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareNEMaskNotDoublePositiveInfinity() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dpinf, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dpinf); @@ -1021,8 +967,7 @@ public static void testCompareNEMaskNotDoublePositiveInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareEQMaskNotDoubleNegativeInfinity() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, dninf, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.EQ, da, dninf); @@ -1034,8 +979,7 @@ public static void testCompareEQMaskNotDoubleNegativeInfinity() { @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "asimd", "true", "avx2", "true", "rvv", "true" }) public static void testCompareNEMaskNotDoubleNegativeInfinity() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.NE, da, dninf, (m) -> { return m.not(); }); verifyResultsDouble(D_SPECIES, VectorOperators.NE, da, dninf); @@ -1048,16 +992,13 @@ public static void testCompareNEMaskNotDoubleNegativeInfinity() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "avx2", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }) public static void testCompareMaskNotByteNegative() { testCompareMaskNotByte(B_SPECIES, VectorOperators.EQ, (m) -> { // The vector mask is used multiple times. @@ -1074,16 +1015,13 @@ public static void testCompareMaskNotByteNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "avx2", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }) public static void testCompareMaskNotShortNegative() { testCompareMaskNotShort(S_SPECIES, VectorOperators.EQ, (m) -> { // The vector mask is used multiple times. @@ -1100,16 +1038,13 @@ public static void testCompareMaskNotShortNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "avx2", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }) public static void testCompareMaskNotIntNegative() { testCompareMaskNotInt(I_SPECIES, VectorOperators.EQ, (m) -> { // The vector mask is used multiple times. @@ -1126,16 +1061,13 @@ public static void testCompareMaskNotIntNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V, "= 2", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "avx2", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }) public static void testCompareMaskNotLongNegative() { testCompareMaskNotLong(L_SPECIES, VectorOperators.EQ, (m) -> { // The vector mask is used multiple times. @@ -1152,16 +1084,13 @@ public static void testCompareMaskNotLongNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) @IR(counts = { IRNode.XOR_V, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureAnd = { "avx2", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }) public static void testCompareMaskNotFloatNegative() { testCompareMaskNotFloat(F_SPECIES, VectorOperators.EQ, fa, fb, (m) -> { // The vector mask is used multiple times. @@ -1182,16 +1111,13 @@ public static void testCompareMaskNotFloatNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) @IR(counts = { IRNode.XOR_V, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V, "= 3", IRNode.VECTOR_MASK_CMP, "= 3" }, - applyIfCPUFeatureAnd = { "avx2", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true" }) public static void testCompareMaskNotDoubleNegative() { testCompareMaskNotDouble(D_SPECIES, VectorOperators.EQ, da, db, (m) -> { // The vector mask is used multiple times. @@ -1230,18 +1156,15 @@ public static void testCompareMaskNotDoubleNegative() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareEQMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.EQ, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.EQ); @@ -1250,18 +1173,15 @@ public static void testCompareEQMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareNEMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.NE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.NE); @@ -1270,18 +1190,15 @@ public static void testCompareNEMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareLTMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.LT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.LT); @@ -1290,18 +1207,15 @@ public static void testCompareLTMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareGTMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.GT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.GT); @@ -1310,18 +1224,15 @@ public static void testCompareGTMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareLEMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.LE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.LE); @@ -1330,18 +1241,15 @@ public static void testCompareLEMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareGEMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.GE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.GE); @@ -1350,18 +1258,15 @@ public static void testCompareGEMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareULTMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.ULT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.ULT); @@ -1370,18 +1275,15 @@ public static void testCompareULTMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareUGTMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.UGT, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.UGT); @@ -1390,18 +1292,15 @@ public static void testCompareUGTMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareULEMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.ULE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.ULE); @@ -1410,18 +1309,15 @@ public static void testCompareULEMaskNotByteCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "sve", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "sve", "true" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareUGEMaskNotByteCast() { testCompareMaskNotByte(ByteVector.SPECIES_64, VectorOperators.UGE, (m) -> { return m.cast(ShortVector.SPECIES_128).not(); }); verifyResultsByte(ByteVector.SPECIES_64, VectorOperators.UGE); @@ -1431,17 +1327,15 @@ public static void testCompareUGEMaskNotByteCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareEQMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.EQ, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.EQ); @@ -1453,17 +1347,15 @@ public static void testCompareEQMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareNEMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.NE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.NE); @@ -1475,17 +1367,15 @@ public static void testCompareNEMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareLTMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.LT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.LT); @@ -1497,17 +1387,15 @@ public static void testCompareLTMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareGTMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.GT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.GT); @@ -1519,17 +1407,15 @@ public static void testCompareGTMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareLEMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.LE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.LE); @@ -1541,17 +1427,15 @@ public static void testCompareLEMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareGEMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.GE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.GE); @@ -1563,17 +1447,15 @@ public static void testCompareGEMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareULTMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.ULT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.ULT); @@ -1585,17 +1467,15 @@ public static void testCompareULTMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareUGTMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.UGT, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.UGT); @@ -1607,17 +1487,15 @@ public static void testCompareUGTMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareULEMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.ULE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.ULE); @@ -1629,17 +1507,15 @@ public static void testCompareULEMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareUGEMaskNotShortCast() { testCompareMaskNotShort(ShortVector.SPECIES_64, VectorOperators.UGE, (m) -> { return IntVector.SPECIES_128.maskAll(true).xor(m.cast(IntVector.SPECIES_128)); }); verifyResultsShort(ShortVector.SPECIES_64, VectorOperators.UGE); @@ -1651,17 +1527,15 @@ public static void testCompareUGEMaskNotShortCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareEQMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.EQ, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.EQ); @@ -1673,17 +1547,15 @@ public static void testCompareEQMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareNEMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.NE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.NE); @@ -1695,17 +1567,15 @@ public static void testCompareNEMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareLTMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.LT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.LT); @@ -1717,17 +1587,15 @@ public static void testCompareLTMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareGTMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.GT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.GT); @@ -1739,17 +1607,15 @@ public static void testCompareGTMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareLEMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.LE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.LE); @@ -1761,17 +1627,15 @@ public static void testCompareLEMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareGEMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.GE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.GE); @@ -1783,17 +1647,15 @@ public static void testCompareGEMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareULTMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.ULT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.ULT); @@ -1805,17 +1667,15 @@ public static void testCompareULTMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareUGTMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.UGT, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.UGT); @@ -1827,17 +1687,15 @@ public static void testCompareUGTMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareULEMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.ULE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.ULE); @@ -1849,17 +1707,15 @@ public static void testCompareULEMaskNotIntCast() { @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 2" }, applyIfCPUFeatureAnd = { "sve", "true" }, - applyIfAnd = { "MaxVectorSize", "= 16", "TieredCompilation", "true" }) + applyIf = { "MaxVectorSize", "= 16" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V_MASK, "= 0", IRNode.XOR_V, "= 0", IRNode.VECTOR_MASK_CMP, "= 2" }, - applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "avx2", "true", "rvv", "true" }) public static void testCompareUGEMaskNotIntCast() { testCompareMaskNotInt(I_SPECIES_FOR_CAST, VectorOperators.UGE, (m) -> { return L_SPECIES_FOR_CAST.maskAll(true).xor(m.cast(L_SPECIES_FOR_CAST)); }); verifyResultsInt(I_SPECIES_FOR_CAST, VectorOperators.UGE); @@ -1870,16 +1726,13 @@ public static void testCompareUGEMaskNotIntCast() { @Test @IR(counts = { IRNode.XOR_V_MASK, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureOr = { "sve", "true", "avx512", "true", "rvv", "true" }) @IR(counts = { IRNode.XOR_V, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "asimd", "true", "sve", "false" }) @IR(counts = { IRNode.XOR_V, "= 1", IRNode.VECTOR_MASK_CMP, "= 1" }, - applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }, - applyIf = { "TieredCompilation", "true" }) + applyIfCPUFeatureAnd = { "avx2", "true", "avx512", "false" }) public static void testMaskedCompareMaskNotNegative() { int expected = F_SPECIES.length(); var ones = FloatVector.broadcast(F_SPECIES, 1f); @@ -1892,17 +1745,6 @@ public static void testMaskedCompareMaskNotNegative() { } public static void main(String[] args) { - // The @IR rules in this test verify that XorVMask(VectorMaskCmp, maskAll(true)) - // is folded away, i.e. that no XorV/XorVMask node survives. IncrementalInlineVector - // is enabled by default; when a vector intrinsic fails to intrinsify, inlining its - // fallback implementation enlarges the compilation unit and, under unstable profiling, - // may prevent AbstractMask::intoArray() from being inlined. When intoArray() is not - // inlined, the mask must be boxed before the call, and during VectorBoxNode - // scalarization a VectorStoreMask user is added to the VectorMaskCmp node. The extra - // out-edge raises VectorMaskCmp's out-count, which inhibits the fold and leaves the - // XorVMask/XorV nodes the rules expect to be absent. This only happens under - // unstable profiling (which makes the intoArray inlining decision non-deterministic); - // under the default profiling the fold is stable. TestFramework testFramework = new TestFramework(); testFramework.setDefaultWarmup(10000) .addFlags("--add-modules=jdk.incubator.vector") diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorUMinMaxReductionTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorUMinMaxReductionTest.java index 4c753d91afdf..a113663027b0 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorUMinMaxReductionTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorUMinMaxReductionTest.java @@ -34,7 +34,7 @@ /** * @test - * @bug 8372980 + * @bug 8372980 8391895 * @key randomness * @summary Add intrinsic support for unsigned min/max reduction operations * @library /test/lib / @@ -141,7 +141,7 @@ private static void verifyLong(VectorSpecies species, long got, long init, @Test @IR(counts = {IRNode.UMIN_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testByteUMin() { byte got = ByteVector.fromArray(B_SPECIES, ba, 0).reduceLanes(VectorOperators.UMIN); verifyByte(B_SPECIES, got, BYTE_UMIN_IDENTITY, VectorMath::minUnsigned, false); @@ -149,7 +149,7 @@ public static void testByteUMin() { @Test @IR(counts = {IRNode.UMAX_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testByteUMax() { byte got = ByteVector.fromArray(B_SPECIES, ba, 0).reduceLanes(VectorOperators.UMAX); verifyByte(B_SPECIES, got, BYTE_UMAX_IDENTITY, VectorMath::maxUnsigned, false); @@ -157,7 +157,7 @@ public static void testByteUMax() { @Test @IR(counts = {IRNode.UMIN_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testByteUMinMasked() { byte got = ByteVector.fromArray(B_SPECIES, ba, 0) .reduceLanes(VectorOperators.UMIN, @@ -167,7 +167,7 @@ public static void testByteUMinMasked() { @Test @IR(counts = {IRNode.UMAX_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testByteUMaxMasked() { byte got = ByteVector.fromArray(B_SPECIES, ba, 0) .reduceLanes(VectorOperators.UMAX, @@ -179,7 +179,7 @@ public static void testByteUMaxMasked() { @Test @IR(counts = {IRNode.UMIN_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testShortUMin() { short got = ShortVector.fromArray(S_SPECIES, sa, 0).reduceLanes(VectorOperators.UMIN); verifyShort(S_SPECIES, got, SHORT_UMIN_IDENTITY, VectorMath::minUnsigned, false); @@ -187,7 +187,7 @@ public static void testShortUMin() { @Test @IR(counts = {IRNode.UMAX_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testShortUMax() { short got = ShortVector.fromArray(S_SPECIES, sa, 0).reduceLanes(VectorOperators.UMAX); verifyShort(S_SPECIES, got, SHORT_UMAX_IDENTITY, VectorMath::maxUnsigned, false); @@ -195,7 +195,7 @@ public static void testShortUMax() { @Test @IR(counts = {IRNode.UMIN_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testShortUMinMasked() { short got = ShortVector.fromArray(S_SPECIES, sa, 0) .reduceLanes(VectorOperators.UMIN, @@ -205,7 +205,7 @@ public static void testShortUMinMasked() { @Test @IR(counts = {IRNode.UMAX_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testShortUMaxMasked() { short got = ShortVector.fromArray(S_SPECIES, sa, 0) .reduceLanes(VectorOperators.UMAX, @@ -217,7 +217,7 @@ public static void testShortUMaxMasked() { @Test @IR(counts = {IRNode.UMIN_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testIntUMin() { int got = IntVector.fromArray(I_SPECIES, ia, 0).reduceLanes(VectorOperators.UMIN); verifyInt(I_SPECIES, got, INT_UMIN_IDENTITY, VectorMath::minUnsigned, false); @@ -225,7 +225,7 @@ public static void testIntUMin() { @Test @IR(counts = {IRNode.UMAX_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testIntUMax() { int got = IntVector.fromArray(I_SPECIES, ia, 0).reduceLanes(VectorOperators.UMAX); verifyInt(I_SPECIES, got, INT_UMAX_IDENTITY, VectorMath::maxUnsigned, false); @@ -233,7 +233,7 @@ public static void testIntUMax() { @Test @IR(counts = {IRNode.UMIN_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testIntUMinMasked() { int got = IntVector.fromArray(I_SPECIES, ia, 0) .reduceLanes(VectorOperators.UMIN, @@ -243,7 +243,7 @@ public static void testIntUMinMasked() { @Test @IR(counts = {IRNode.UMAX_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"}) public static void testIntUMaxMasked() { int got = IntVector.fromArray(I_SPECIES, ia, 0) .reduceLanes(VectorOperators.UMAX, @@ -255,7 +255,7 @@ public static void testIntUMaxMasked() { @Test @IR(counts = {IRNode.UMIN_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx512vl", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx512vl", "true", "rvv", "true"}) public static void testLongUMin() { long got = LongVector.fromArray(L_SPECIES, la, 0).reduceLanes(VectorOperators.UMIN); verifyLong(L_SPECIES, got, LONG_UMIN_IDENTITY, VectorMath::minUnsigned, false); @@ -263,7 +263,7 @@ public static void testLongUMin() { @Test @IR(counts = {IRNode.UMAX_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx512vl", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx512vl", "true", "rvv", "true"}) public static void testLongUMax() { long got = LongVector.fromArray(L_SPECIES, la, 0).reduceLanes(VectorOperators.UMAX); verifyLong(L_SPECIES, got, LONG_UMAX_IDENTITY, VectorMath::maxUnsigned, false); @@ -271,7 +271,7 @@ public static void testLongUMax() { @Test @IR(counts = {IRNode.UMIN_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx512vl", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx512vl", "true", "rvv", "true"}) public static void testLongUMinMasked() { long got = LongVector.fromArray(L_SPECIES, la, 0) .reduceLanes(VectorOperators.UMIN, @@ -281,7 +281,7 @@ public static void testLongUMinMasked() { @Test @IR(counts = {IRNode.UMAX_REDUCTION_V, "= 1"}, - applyIfCPUFeatureOr = {"asimd", "true", "avx512vl", "true"}) + applyIfCPUFeatureOr = {"asimd", "true", "avx512vl", "true", "rvv", "true"}) public static void testLongUMaxMasked() { long got = LongVector.fromArray(L_SPECIES, la, 0) .reduceLanes(VectorOperators.UMAX, diff --git a/test/hotspot/jtreg/gc/metaspace/TestMetaspaceFirstGC.java b/test/hotspot/jtreg/gc/metaspace/TestMetaspaceFirstGC.java index f832ffdfc2aa..d8ba25ca9f54 100644 --- a/test/hotspot/jtreg/gc/metaspace/TestMetaspaceFirstGC.java +++ b/test/hotspot/jtreg/gc/metaspace/TestMetaspaceFirstGC.java @@ -23,14 +23,17 @@ /* * @test TestMetaspaceFirstGC - * @bug 8208250 8391711 - * @summary Verify that the first metaspace GC is triggered when metaspace reaches the MetaspaceSize threshold + * @bug 8208250 8391711 8392597 + * @summary Verify that the first metadata GC request seen after startup is made when metaspace reaches the MetaspaceSize threshold * @requires vm.hasJFR + * @requires vm.gc != "Shenandoah" * @library /test/lib - * @run main/othervm -Xms200m -XX:StartFlightRecording:name=startup TestMetaspaceFirstGC - * @run main/othervm -Xms200m -XX:MetaspaceSize=10m -XX:StartFlightRecording:name=startup TestMetaspaceFirstGC 10m - * @run main/othervm -Xms200m -XX:MetaspaceSize=50m -XX:StartFlightRecording:name=startup TestMetaspaceFirstGC 50m - * @run main/othervm -Xms200m -XX:MetaspaceSize=99m -XX:StartFlightRecording:name=startup TestMetaspaceFirstGC 99m + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xms200m -XX:MinMetaspaceFreeRatio=0 -XX:StartFlightRecording:name=startup TestMetaspaceFirstGC + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xms200m -XX:MinMetaspaceFreeRatio=0 -XX:MetaspaceSize=10m -XX:StartFlightRecording:name=startup TestMetaspaceFirstGC 10m + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xms200m -XX:MinMetaspaceFreeRatio=0 -XX:MetaspaceSize=50m -XX:StartFlightRecording:name=startup TestMetaspaceFirstGC 50m + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xms200m -XX:MinMetaspaceFreeRatio=0 -XX:MetaspaceSize=99m -XX:StartFlightRecording:name=startup TestMetaspaceFirstGC 99m */ import java.lang.management.ManagementFactory; @@ -40,27 +43,59 @@ import java.net.URL; import java.net.URLClassLoader; import java.nio.file.Path; +import java.time.Instant; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import jdk.jfr.Event; import jdk.jfr.FlightRecorder; +import jdk.jfr.Name; import jdk.jfr.Recording; +import jdk.jfr.StackTrace; import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedFrame; +import jdk.jfr.consumer.RecordedStackTrace; import jdk.jfr.consumer.RecordingFile; import jdk.jfr.consumer.RecordingStream; import jdk.test.lib.Asserts; import jdk.test.lib.jfr.EventNames; +import jdk.test.whitebox.WhiteBox; import jtreg.SkippedException; public class TestMetaspaceFirstGC { private static int classCounter = 0; + // written on the loading thread right before every class load, on the same clock as the + // VM events, the one right before the failed allocation is the closest look at the request + @Name("TestMetaspaceFirstGC.LoadSample") + @StackTrace(false) + private static class LoadSample extends Event { + long committed; + long threshold; + } + + // the candidate allocation failure happened inside loadOneClass + private static boolean fromLoadOneClass(RecordedEvent event) { + RecordedStackTrace stackTrace = event.getStackTrace(); + if (stackTrace == null) { + return false; + } + for (RecordedFrame frame : stackTrace.getFrames()) { + if (frame.getMethod().getType().getName().equals("TestMetaspaceFirstGC") + && frame.getMethod().getName().equals("loadOneClass")) { + return true; + } + } + return false; + } + // kept alive so no collection can unload them before the threshold is reached + private static final List loaders = new ArrayList<>(); - // Counted down from the JFR stream when a collection with cause "Metadata GC Threshold" - // arrives, so the event is already in hand when loading stops. + // Counted down from the JFR stream when a metadata allocation failure inside loadOneClass + // arrives, whether it was the first request is decided afterwards from the recording. private static final CountDownLatch metadataGC = new CountDownLatch(1); public interface Dummy {} @@ -78,117 +113,175 @@ public static void main(String[] args) throws Exception { expectedSize = parseSize(args[0]); } - long committedAtStart = ManagementFactory.getMemoryPoolMXBeans().stream() - .filter(p -> p.getName().equals("Metaspace")) - .mapToLong(p -> p.getUsage().getCommitted()) - .findFirst() - .orElseThrow(() -> new RuntimeException("Metaspace pool not found")); - System.out.println("Metaspace committed at start: " + committedAtStart); - if (expectedSize > 0 && committedAtStart >= expectedSize) { - // the first metadata GC already happened during VM startup, nothing left to observe - throw new SkippedException("metaspace committed at start (" + committedAtStart - + ") already at MetaspaceSize (" + expectedSize + ")"); - } - List events; try (RecordingStream rs = new RecordingStream()) { - rs.enable(EventNames.GarbageCollection); - rs.onEvent(EventNames.GarbageCollection, event -> { - if ("Metadata GC Threshold".equals(event.getString("cause"))) { + // a concurrent collector may fold the requested GC into a cycle that is already + // running and never emit the cause, the failed allocation inside loadOneClass is the + // candidate, whether a GC was really asked for is checked afterwards + rs.enable(EventNames.MetaspaceAllocationFailure).withStackTrace(); + rs.onEvent(EventNames.MetaspaceAllocationFailure, event -> { + if (fromLoadOneClass(event)) { metadataGC.countDown(); } }); rs.startAsync(); + // load what the measured window touches before it opens, the recording is checked + // afterwards for any other allocation failure inside it + WhiteBox.getWhiteBox().metaspaceCapacityUntilGC(); + getMetaspaceCommitted(); + getMetaspaceUsed(); + new LoadSample().commit(); + Instant loadingStart = Instant.now(); + // metaspace commits in 64K granules and one class load allocates a few KB, the sample + // is taken right before the load that failed + long tolerance = 1024 * 1024; + long initialThreshold = WhiteBox.getWhiteBox().metaspaceCapacityUntilGC(); + System.out.println("Initial metaspace GC threshold: " + initialThreshold); + long metaspaceSize = WhiteBox.getWhiteBox().getSizeTVMFlag("MetaspaceSize"); + if (expectedSize > 0) { + Asserts.assertEquals(metaspaceSize, expectedSize, "MetaspaceSize as set on the command line"); + } else { + // the platform dependent ergonomic default + Asserts.assertGreaterThan(metaspaceSize, 11_500_000L, "default MetaspaceSize (" + metaspaceSize + ") too small"); + Asserts.assertLessThan(metaspaceSize, 22_500_000L, "default MetaspaceSize (" + metaspaceSize + ") too large"); + } + if (initialThreshold != metaspaceSize) { + // startup already moved the threshold, the first metadata GC request can't be measured + throw new SkippedException("threshold already at " + initialThreshold + + ", not MetaspaceSize " + metaspaceSize); + } - // Load classes until a metaspace-triggered GC happens - loadClassesUntilGC(50000); + // Load classes until the metadata allocation failure shows up + try { + loadClassesUntilGC(50000); + } catch (RuntimeException e) { + System.out.println("Threshold now " + WhiteBox.getWhiteBox().metaspaceCapacityUntilGC() + + ", metaspace used=" + getMetaspaceUsed()); + for (Recording r : FlightRecorder.getFlightRecorder().getRecordings()) { + if ("startup".equals(r.getName())) { + r.dump(Path.of("metaspace-first-gc-" + (expectedSize > 0 ? args[0] : "default") + "-failed.jfr")); + } + } + throw e; + } + // one more sample closes the window of the last candidate before anything is released + LoadSample end = new LoadSample(); + end.committed = getMetaspaceCommitted(); + end.threshold = WhiteBox.getWhiteBox().metaspaceCapacityUntilGC(); + end.commit(); + loaders.clear(); rs.stop(); - // The startup recording has run since VM start, so it holds the GC's "Before GC" - // summary and the first threshold change even when the first metadata GC happens - // during JFR initialization, before this stream existed. + // The startup recording begins during VM initialization, before this stream existed, + // so it holds the earlier events too, anything before JFR started is out of reach. Recording startup = FlightRecorder.getFlightRecorder().getRecordings().stream() .filter(r -> "startup".equals(r.getName())) .findFirst() .orElseThrow(() -> new RuntimeException("startup recording not found")); startup.stop(); - Path dump = Path.of("metaspace-first-gc.jfr"); + Path dump = Path.of("metaspace-first-gc-" + (expectedSize > 0 ? args[0] : "default") + ".jfr"); startup.dump(dump); events = new ArrayList<>(RecordingFile.readAllEvents(dump)); events.sort(Comparator.comparing(RecordedEvent::getStartTime)); - // Find first GarbageCollection with cause "Metadata GC Threshold" - RecordedEvent gcEvent = null; + // The candidate is the first failed metadata allocation inside loadOneClass. A threshold + // change or a metadata GC starting before the next sample shows the collector was asked, + // the window may hold more failures and the collection may finish later. The sample before + // the failing load gives committed and the threshold, committed has to be at the threshold + // within the tolerance, below it the request was premature. A later threshold change is not + // guaranteed, when there is one it starts at or above the sampled threshold. A failed + // allocation elsewhere or a threshold change before the candidate skips the run, a sampled + // threshold that differs from the initial one with no change recorded is a failure. + // Shenandoah without class unloading expands without asking and is excluded. + RecordedEvent request = null; + int startupFailures = 0; + int earlierFailures = 0; for (RecordedEvent event : events) { - if (event.getEventType().getName().equals(EventNames.GarbageCollection)) { - String cause = event.getString("cause"); - if ("Metadata GC Threshold".equals(cause)) { - gcEvent = event; - break; - } + if (!event.getEventType().getName().equals(EventNames.MetaspaceAllocationFailure)) { + continue; } + if (!event.getStartTime().isAfter(loadingStart)) { + startupFailures++; + continue; + } + if (fromLoadOneClass(event)) { + request = event; + break; + } + earlierFailures++; } - - if (gcEvent == null) { - throw new RuntimeException("No GC with cause 'Metadata GC Threshold' found"); - } - - int gcId = gcEvent.getInt("gcId"); - System.out.println("Found Metadata GC Threshold GC, gcId=" + gcId); - - // Find matching MetaspaceSummary with same gcId and when="Before GC" - RecordedEvent msEvent = null; + Asserts.assertNotNull(request, "no metaspace allocation failure inside loadOneClass"); + Instant nextLoad = null; for (RecordedEvent event : events) { - if (event.getEventType().getName().equals(EventNames.MetaspaceSummary)) { - if (event.getInt("gcId") == gcId && "Before GC".equals(event.getString("when"))) { - msEvent = event; - break; - } + if (event.getEventType().getName().equals("TestMetaspaceFirstGC.LoadSample") + && event.getStartTime().isAfter(request.getStartTime())) { + nextLoad = event.getStartTime(); + break; } } - - if (msEvent == null) { - for (RecordedEvent e : events) { - if (e.getEventType().getName().equals(EventNames.MetaspaceSummary)) { - System.out.println("MetaspaceSummary gcId=" + e.getInt("gcId") + " when=" + e.getString("when")); + long thresholdAfterRequest = -1; + boolean metadataGcSeen = false; + boolean summaryLogged = false; + int changesBefore = 0; + for (RecordedEvent event : events) { + if (!event.getStartTime().isAfter(loadingStart)) { + continue; + } + String type = event.getEventType().getName(); + boolean beforeRequest = event.getStartTime().isBefore(request.getStartTime()); + if (type.equals(EventNames.MetaspaceGCThreshold)) { + if (beforeRequest) { + changesBefore++; + System.out.println("Threshold changed before the candidate: " + event.getLong("oldValue") + + " -> " + event.getLong("newValue") + " by " + event.getString("updater")); + } else if (thresholdAfterRequest < 0 + && (nextLoad == null || !event.getStartTime().isAfter(nextLoad))) { + thresholdAfterRequest = event.getLong("oldValue"); } + } else if (type.equals(EventNames.GarbageCollection) && !beforeRequest + && (nextLoad == null || !event.getStartTime().isAfter(nextLoad)) + && "Metadata GC Threshold".equals(event.getString("cause"))) { + metadataGcSeen = true; + } else if (type.equals(EventNames.MetaspaceSummary) && !beforeRequest && !summaryLogged) { + summaryLogged = true; + System.out.println("Summary after the candidate: " + event.getString("when") + " gcId=" + + event.getLong("gcId") + " committed=" + event.getLong("metaspace.committed") + + " gcThreshold=" + event.getLong("gcThreshold")); } - throw new RuntimeException("No MetaspaceSummary 'Before GC' found for gcId=" + gcId); } - - long committed = msEvent.getLong("metaspace.committed"); - long gcThreshold = msEvent.getLong("gcThreshold"); - System.out.println("MetaspaceSummary: committed=" + committed + " gcThreshold=" + gcThreshold); - - // committed should be reasonably close to gcThreshold - long tolerance = 5 * 1024 * 1024; // 5MB tolerance - Asserts.assertLessThanOrEqual(Math.abs(committed - gcThreshold), tolerance, - "committed (" + committed + ") should be close to gcThreshold (" + gcThreshold + ")"); - // The threshold at which the first metadata GC was requested. A concurrent collector - // expands it and keeps allocating during the GC, the earliest change keeps the original value. - long firstThreshold = gcThreshold; + if (startupFailures > 0 || earlierFailures > 0 || changesBefore > 0) { + throw new SkippedException(startupFailures + " allocation failures before loading started, " + + earlierFailures + " other allocation failures and " + changesBefore + + " threshold changes before the candidate, the first metadata GC request can't be measured"); + } + if (thresholdAfterRequest < 0 && !metadataGcSeen) { + // nothing shows a GC was asked for, the retry may have gone through without one + throw new SkippedException("no threshold change and no metadata GC starting in the candidate's window"); + } + RecordedEvent atRequest = null; for (RecordedEvent event : events) { - if (event.getEventType().getName().equals(EventNames.MetaspaceGCThreshold)) { - firstThreshold = event.getLong("oldValue"); - System.out.println("First threshold change: " + firstThreshold + " -> " - + event.getLong("newValue") + " by " + event.getString("updater")); + if (!event.getEventType().getName().equals("TestMetaspaceFirstGC.LoadSample")) { + continue; + } + if (event.getStartTime().isAfter(request.getStartTime())) { break; } + atRequest = event; } - - // If explicit MetaspaceSize given, the first GC must have been triggered at it - if (expectedSize > 0) { - Asserts.assertLessThanOrEqual(Math.abs(firstThreshold - expectedSize), tolerance, - "first threshold (" + firstThreshold + ") should be close to MetaspaceSize (" + expectedSize + ")"); - System.out.println("first threshold matches expected MetaspaceSize=" + expectedSize); - } else { - // No explicit MetaspaceSize, check default range (~12MB to ~20MB per tuning guide) - Asserts.assertGreaterThan(firstThreshold, 11_500_000L, - "default threshold (" + firstThreshold + ") too small"); - Asserts.assertLessThan(firstThreshold, 22_500_000L, - "default threshold (" + firstThreshold + ") too large"); - System.out.println("first threshold in expected default range"); + Asserts.assertNotNull(atRequest, "no sample before the request"); + long committedAtRequest = atRequest.getLong("committed"); + long thresholdAtRequest = atRequest.getLong("threshold"); + System.out.println("Before the failing load: committed=" + committedAtRequest + + " threshold=" + thresholdAtRequest + + (thresholdAfterRequest < 0 ? ", no threshold change in the window" : ", next change in the window from " + thresholdAfterRequest)); + if (thresholdAfterRequest >= 0) { + Asserts.assertGreaterThanOrEqual(thresholdAfterRequest, thresholdAtRequest, + "the threshold change after the request should start at or above the sampled threshold"); } + Asserts.assertLessThanOrEqual(Math.abs(thresholdAtRequest - committedAtRequest), tolerance, + "committed before the request (" + committedAtRequest + ") should be at the threshold (" + thresholdAtRequest + ")"); + Asserts.assertEquals(thresholdAtRequest, initialThreshold, + "the first metadata GC should have been requested at the initial threshold"); System.out.println("PASSED"); } @@ -196,30 +289,43 @@ public static void main(String[] args) throws Exception { private static void loadClassesUntilGC(int maxIterations) throws InterruptedException { for (int i = 0; i < maxIterations; i++) { + LoadSample sample = new LoadSample(); + sample.committed = getMetaspaceCommitted(); + sample.threshold = WhiteBox.getWhiteBox().metaspaceCapacityUntilGC(); + sample.commit(); loadOneClass(); if (metadataGC.getCount() == 0) { - System.out.println("Metadata GC seen after " + (i + 1) + " class loads, metaspace used=" + getMetaspaceUsed()); + System.out.println("Metadata allocation failure seen after " + (i + 1) + " load attempts, metaspace used=" + getMetaspaceUsed()); return; } } - // a concurrent collector may still be running the collection + // the event may still be on its way from the stream if (metadataGC.await(60, TimeUnit.SECONDS)) { - System.out.println("Metadata GC seen after " + maxIterations + " class loads, metaspace used=" + getMetaspaceUsed()); + System.out.println("Metadata allocation failure seen after " + maxIterations + " load attempts, metaspace used=" + getMetaspaceUsed()); return; } - throw new RuntimeException("No metaspace GC after " + maxIterations + " class loads"); + throw new RuntimeException("No metadata allocation failure inside loadOneClass after " + maxIterations + " load attempts"); } private static void loadOneClass() { try { String jarUrl = "file:" + (classCounter++) + ".jar"; URLClassLoader cl = new URLClassLoader(new URL[]{new URL(jarUrl)}); + loaders.add(cl); Proxy.newProxyInstance(cl, new Class[]{Dummy.class}, new DummyHandler()); } catch (Exception e) { throw new RuntimeException(e); } } + private static long getMetaspaceCommitted() { + return ManagementFactory.getMemoryPoolMXBeans().stream() + .filter(p -> p.getName().equals("Metaspace")) + .mapToLong(p -> p.getUsage().getCommitted()) + .findFirst() + .orElseThrow(() -> new RuntimeException("Metaspace pool not found")); + } + private static long getMetaspaceUsed() { return ManagementFactory.getMemoryPoolMXBeans().stream() .filter(p -> p.getName().equals("Metaspace")) diff --git a/test/hotspot/jtreg/gc/shenandoah/generational/TestRemSetBalance.java b/test/hotspot/jtreg/gc/shenandoah/generational/TestRemSetBalance.java new file mode 100644 index 000000000000..41a9cb83cc62 --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/generational/TestRemSetBalance.java @@ -0,0 +1,186 @@ +/* + * 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. + * + */ + +/* This test is marked manual because it is known to require human + * interpretation of the results. The data gathered and reported by + * the test can be informative, though failure or passing of the test + * is not conclusive. + */ + +/* + * @test id=generational + * @summary Test that scanning of the remembered set is well balanced + * @requires vm.gc.Shenandoah + * @requires vm.flagless + * @requires os.maxMemory >= 10g + * @library /test/lib + * @run main/manual TestRemSetBalance + */ + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Random; +import java.util.Scanner; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestRemSetBalance { + + private static boolean parse_input(List stdout) { + Object[] lines = stdout.toArray(); + for (int index = 0; index < lines.length; index++) { + String line = (String) lines[index]; + int line_no = index + 1; + String[] tokens = line.split("\\s+"); + if (tokens.length > 8) { + // We are looking for output lines of the following format: + // [21.947s][info][gc,stats] RS: Work 662295 us total, per worker: 169895, 155334, 167446, 169620, ---, ---, ---, ---, + // We want to enforce low variance in the us consumed by individual GC workers, representing good balance. + if (tokens[1].equals("RS:") && tokens[2].equals("Work") && tokens[4].equals("us") + && tokens[5].equals("total,") && tokens[6].equals("per") && tokens[7].equals("worker:")) { + int min_work = 0x7fff_ffff; + int max_work = 0; + int total_work = 0; + int num_workers = 0; + for (int i = 8; i < tokens.length; i++) { + if (!tokens[i].equals("---,")) { + num_workers++; + // Need to strip the "," from end of tokens[i] + int value = Integer.parseInt(tokens[i].substring(0, tokens[i].length() - 1)); + total_work += value; + if (value > max_work) { + max_work = value; + } + if (value < min_work) { + min_work = value; + } + } + } + if (min_work < 10) { + if (max_work > 100) { + System.out.println("Out of balance: max work: " + max_work + " is greater than 100 when min work: " + min_work + + " is smaller than 10 at line " + line_no); + System.out.println(" line: " + line); + return false; + } + } else { + int average = total_work / num_workers; + // Allow deviation from average plus or minus 9.375%) + int deviation_bound = (3 * average) / 32; + if (max_work > average + deviation_bound) { + System.out.println("Out of balance: max work: " + max_work + " is greater than average work: " + average + + " plus bound: " + deviation_bound + " at line " + line_no); + System.out.println(" line: " + line); + return false; + } else if (min_work < average - deviation_bound) { + System.out.println("Out of balance: min work: " + min_work + " is less than average work: " + average + + " minus bound: " + deviation_bound + " at line " + line_no); + System.out.println(" line: " + line); + return false; + } + } + } + } + } + return true; + } + + static int counter = 1_000_000_000; + + private static String newString() { + counter++; + if (counter >= 1_000_010_000) counter = 1_000_000_000; + return "str" + counter; + } + + static final Random r = new Random(); + static Object[] retain; + + // Runs the allocation workload if args[0] matches "test", returning true. args[1], args[2], and args[3] are assumed + // to represent integers. + // Otherwise, returns false. + static boolean run_workload(String[] args) throws Exception { + if (args[0].equals("test")) { + int total = 1000 * Integer.parseInt(args[1]); + int rewrite = total / 100 * Integer.parseInt(args[2]); + long overwrites = 1L * total * Integer.parseInt(args[3]); + if (rewrite <= 0) { + rewrite = 1; + } + retain = new Object[total]; + for (int c = 0; c < total; c++) { + retain[c] = newString(); + } + for (long c = 0; c < overwrites; c++) { + int i = r.nextInt(total) % rewrite; + retain[i] = newString(); + } + return true; + } else { + return false; + } + } + + public static void testRemSet(String... args) throws Exception { + String[] cmds = Arrays.copyOf(args, args.length + 5); + cmds[args.length] = TestRemSetBalance.class.getName(); + cmds[args.length + 1] = "test"; + cmds[args.length + 2] = "3000"; + cmds[args.length + 3] = "50"; + cmds[args.length + 4] = "1000"; + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(cmds); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + List stdout = output.asLines(); + Asserts.assertTrue(parse_input(stdout), "Log has too much variation in remembered set scan times"); + } + + public static void main(String[] args) throws Exception { + if (args.length > 0 && args[0].equals("test")) { + run_workload(args); + return; + } + + testRemSet("-Xlog:gc", + "-Xms8g", + "-Xmx8g", + "-XX:+UseShenandoahGC", + "-XX:ShenandoahGCMode=generational", + "-Xlog:gc+stats", + "-XX:+UseCompactObjectHeaders" + ); + + testRemSet("-Xlog:gc", + "-Xms8g", + "-Xmx8g", + "-XX:+UseShenandoahGC", + "-XX:ShenandoahGCMode=generational", + "-Xlog:gc+stats", + "-XX:-UseCompactObjectHeaders" + ); + } +} diff --git a/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java b/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java index 5ed6999734b1..ebea2d989fb5 100644 --- a/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java +++ b/test/hotspot/jtreg/runtime/CompressedOops/CompressedCPUSpecificClassSpaceReservation.java @@ -53,7 +53,7 @@ public class CompressedCPUSpecificClassSpaceReservation { // +SimulateFullAddressSpace (VM won't be able to reserve heap). Therefore we exclude the test for windows // for now. - private static void do_test(boolean CDS) throws IOException { + private static void do_test(boolean CDS, boolean COH) throws IOException { // We start the VM with -XX:+SimulateFullAdressSpace, which means the JVM will go through all motions // of reserving the cds+class space, but never succeed. That means we see every single allocation attempt. // We start with -Xlog options enabled. The expected output goes like this: @@ -62,22 +62,33 @@ private static void do_test(boolean CDS) throws IOException { "-Xshare:" + (CDS ? "on" : "off"), "-Xmx128m", "-XX:CompressedClassSpaceSize=128m", - "-XX:-UseCompactObjectHeaders", + "-XX:" + (COH ? "+" : "-") +"UseCompactObjectHeaders", "-Xlog:metaspace*", "-Xlog:metaspace+map=trace", "-Xlog:os+map=trace", "-XX:+SimulateFullAddressSpace", // So that no resevation attempt will succeed "-version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - final String tryReserveForUnscaled = "reserve_between (range [0x0000000000000000-0x0000000100000000)"; + final boolean doNotOptimizeForZeroBased = CDS || COH; final String tryReserveBelow4G = "reserve_between (range [0x0000000000000000-0x0000000100000000)"; - final String tryReserveForZeroBased = "reserve_between (range [0x0000000100000000-0x0000000800000000)"; + // The encoding range for unscaled depends on the size of narrow class pointer, + // which is dictated by the status of Compressed Object Headers: + // +COH: [0, 2^22) + // -COH: [0, 2^32) + final String tryReserveForUnscaled = "reserve_between (range [" + + (COH ? "0x0000000000000000-0x0000000000400000" : "0x0000000000000000-0x0000000100000000") + ")"; + // The encoding range for zero based depends on the size of narrow class pointer and max shift, + // which are dictated by the status of Compressed Object Headers: + // +COH: [2^22, 2^32) + // -COH: [0, 2^35) + final String tryReserveForZeroBased = "reserve_between (range [" + + (COH ? "0x0000000000400000-0x0000000100000000" : "0x0000000100000000-0x0000000800000000") + ")"; // Failing zero-based allocation, platforms will often attempt allocation suitable for a disjointed move: // an insert of the base address bits into the register holding the nK. That requires the base to not // intersect with nK bits (for simplicity, we always assume nK range of 32bits). // The upper limit of this reservation attempt is platform-dependent, though. final String tryReserveFor16bitMoveIntoQ3Regex = "reserve_between.*0x0000000100000000-0x\\d{8}00000000.*alignment 0x100000000"; if (Platform.isAArch64()) { - if (CDS) { + if (doNotOptimizeForZeroBased) { output.shouldNotContain(tryReserveForUnscaled); } else { output.shouldContain(tryReserveForUnscaled); @@ -85,7 +96,7 @@ private static void do_test(boolean CDS) throws IOException { output.shouldContain("Trying to reserve at an EOR-compatible address"); output.shouldNotContain(tryReserveForZeroBased); } else if (Platform.isPPC()) { - if (CDS) { + if (doNotOptimizeForZeroBased) { output.shouldNotContain(tryReserveForUnscaled); output.shouldNotContain(tryReserveForZeroBased); } else { @@ -101,7 +112,7 @@ private static void do_test(boolean CDS) throws IOException { output.shouldContain("reserve_between (range [0x0000100000000000-0xffffffffffffffff)"); } else if (Platform.isS390x()) { output.shouldContain(tryReserveBelow4G); // unconditionally - if (CDS) { + if (doNotOptimizeForZeroBased) { output.shouldNotContain(tryReserveForZeroBased); } else { output.shouldContain(tryReserveForZeroBased); @@ -109,7 +120,7 @@ private static void do_test(boolean CDS) throws IOException { output.shouldMatch(tryReserveFor16bitMoveIntoQ3Regex); } else if (Platform.isX64()) { output.shouldContain(tryReserveBelow4G); - if (CDS) { + if (doNotOptimizeForZeroBased) { output.shouldNotContain(tryReserveForZeroBased); } else { output.shouldContain(tryReserveForZeroBased); @@ -146,11 +157,14 @@ private static void do_test(boolean CDS) throws IOException { } public static void main(String[] args) throws Exception { - // SapMachine 2025-06-11: reduce number of cds/jsa archives - // -Xshare:on can only be used for a configuration for which we have a jsa cds archive. - //System.out.println("Test with CDS"); - //do_test(true); - System.out.println("Test without CDS"); - do_test(false); + // SapMachine 2026-10-19: -Xshare:on requires a jsa archive; skip CDS without COH as we don't have all jsa files + //System.out.println("Test with CDS / without COH"); + //do_test(true, false); + System.out.println("Test without CDS / without COH"); + do_test(false, false); + System.out.println("Test with CDS / with COH"); + do_test(true, true); + System.out.println("Test without CDS / with COH"); + do_test(false, true); } } diff --git a/test/hotspot/jtreg/runtime/ErrorHandling/TestSAPSpecificOnOutOfMemoryError.java b/test/hotspot/jtreg/runtime/ErrorHandling/TestSAPSpecificOnOutOfMemoryError.java index 32b82e53c585..12cba8e824c5 100644 --- a/test/hotspot/jtreg/runtime/ErrorHandling/TestSAPSpecificOnOutOfMemoryError.java +++ b/test/hotspot/jtreg/runtime/ErrorHandling/TestSAPSpecificOnOutOfMemoryError.java @@ -65,7 +65,7 @@ public static void main(String[] args) throws Exception { final String aborting_due = "Aborting due to java.lang.OutOfMemoryError"; final String terminating_due = "Terminating due to java.lang.OutOfMemoryError"; - final String java_frames = "Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)"; + final String java_frames = "Java frames: (J=compiled Java code,"; final String a_fatal_error = "# A fatal error has been detected by the Java Runtime Environment"; final String no_core = "CreateCoredumpOnCrash turned off, no core file dumped"; final String yes_core_1 = "Core dump will be written."; // If limit > 0 diff --git a/test/hotspot/jtreg/runtime/cds/MetaspaceAllocGaps.java b/test/hotspot/jtreg/runtime/cds/MetaspaceAllocGaps.java index df297ddbaa34..ce9610d089f6 100644 --- a/test/hotspot/jtreg/runtime/cds/MetaspaceAllocGaps.java +++ b/test/hotspot/jtreg/runtime/cds/MetaspaceAllocGaps.java @@ -42,9 +42,12 @@ public class MetaspaceAllocGaps { public static void main(String[] args) throws Exception { String appJar = ClassFileInstaller.getJarPath("hello.jar"); for (int i = 0; i < 2; i++) { + // Exclude AOT training data for consistency. String compressedOops = "-XX:" + (i == 0 ? "-" : "+") + "UseCompressedOops"; SimpleCDSAppTester.of("MetaspaceAllocGaps" + i) .addVmArgs("-Xlog:aot=debug,aot+alloc=trace", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:-AOTRecordTraining", "-XX:+UseCompactObjectHeaders") .classpath(appJar) .appCommandLine("Hello") diff --git a/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java b/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java index 73f352a1eabf..7822f5d0574f 100644 --- a/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java +++ b/test/hotspot/jtreg/runtime/cds/TestDefaultArchiveLoading.java @@ -29,6 +29,7 @@ * @requires vm.vendor != "SAP SE" * @requires vm.cds * @requires vm.cds.default.archive.available + * @requires vm.cds.nocoops.nocoh.archive.available * @requires vm.cds.write.archived.java.heap * @requires vm.bits == 64 * @library /test/lib @@ -42,6 +43,7 @@ * @summary Test Loading of default archives in all configurations * @requires vm.cds * @requires vm.cds.default.archive.available + * @requires vm.cds.nocoops.archive.available * @requires vm.cds.write.archived.java.heap * @requires vm.bits == 64 * @library /test/lib @@ -57,6 +59,7 @@ * @requires vm.vendor != "SAP SE" * @requires vm.cds * @requires vm.cds.default.archive.available + * @requires vm.cds.nocoh.archive.available * @requires vm.cds.write.archived.java.heap * @requires vm.bits == 64 * @requires vm.gc != "Z" @@ -98,17 +101,6 @@ private static String archiveName(String archiveSuffix) { return "classes" + archiveSuffix + archivePreviewSuffix + ".jsa"; } - private static Path archivePath(String archiveSuffix) { - return Paths.get(System.getProperty("java.home"), "lib", - "server", archiveName(archiveSuffix)); - } - - private static boolean isArchiveAvailable(char coops, char coh, - String archiveSuffix) throws Exception { - Path archive= archivePath(archiveSuffix); - return Files.exists(archive); - } - public static void main(String[] args) throws Exception { if (args.length != 1) { @@ -128,36 +120,20 @@ public static void main(String[] args) throws Exception { case "nocoops_nocoh": coh = coops = '-'; archiveSuffix = "_nocoops_nocoh"; - if (!isArchiveAvailable(coops, coh, archiveSuffix)) { - throw new SkippedException("Skipping test due to " + - archivePath(archiveSuffix).toString() + " not available"); - } break; case "nocoops_coh": coops = '-'; coh = '+'; archiveSuffix = "_nocoops"; - if (!isArchiveAvailable(coops, coh, archiveSuffix)) { - throw new SkippedException("Skipping test due to " + - archivePath(archiveSuffix).toString() + " not available"); - } break; case "coops_nocoh": coops = '+'; coh = '-'; archiveSuffix = "_nocoh"; - if (!isArchiveAvailable(coops, coh, archiveSuffix)) { - throw new SkippedException("Skipping test due to " + - archivePath(archiveSuffix).toString() + " not available"); - } break; case "coops_coh": coh = coops = '+'; archiveSuffix = ""; - if (!isArchiveAvailable(coops, coh, archiveSuffix)) { - throw new SkippedException("Skipping test due to " + - archivePath(archiveSuffix).toString() + " not available"); - } break; default: throw new RuntimeException("Invalid argument " + args[0]); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCompatibleOopCompression.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCompatibleOopCompression.java index 7d557a3b1c77..0aaf2f5fb778 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCompatibleOopCompression.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCompatibleOopCompression.java @@ -26,7 +26,7 @@ /* * @test * @summary Sanity test for -XX:+AOTCompatibleOopCompression - * @requires vm.cds.supports.aot.class.linking + * @requires vm.cds.supports.aot.code.caching * @requires vm.bits == 64 & vm.opt.final.UseCompressedOops == true * @library /test/lib * @build AOTCompatibleOopCompression diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCompileEagerly.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCompileEagerly.java index c740ecd96f5d..76f7faf75f2e 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCompileEagerly.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCompileEagerly.java @@ -83,7 +83,7 @@ public static void main(String[] args) throws Exception { System.out.println("Production Run with AOTCache and eager compilation explicitly ON"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTCache=" + aotCacheFile, - "-XX:+UnlockExperimentalVMOptions", + "-XX:+UnlockDiagnosticVMOptions", "-XX:+AOTCompileEagerly", "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod-eager-on"); @@ -93,7 +93,7 @@ public static void main(String[] args) throws Exception { System.out.println("Production Run with AOTCache and eager compilation explicitly OFF"); pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTCache=" + aotCacheFile, - "-XX:+UnlockExperimentalVMOptions", + "-XX:+UnlockDiagnosticVMOptions", "-XX:-AOTCompileEagerly", "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod-eager-off"); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/TestSetupAOTTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/TestSetupAOTTest.java index 118b4c6af1d3..71aabc710ee2 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/TestSetupAOTTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/aotClassLinking/TestSetupAOTTest.java @@ -27,7 +27,7 @@ * @summary This is a test case for creating an AOT cache using the setup_aot/TestSetupAOT.java program, which * is used for running HotSpot tests in the "AOT mode" * (E.g., make test JTREG=AOT_JDK=true TEST=open/test/hotspot/jtreg/runtime/invokedynamic) - * @requires vm.cds + * @requires vm.cds.supports.aot.class.linking * @library /test/lib /test/setup_aot * @build TestSetupAOTTest JavacBenchApp TestSetupAOT * @run driver jdk.test.lib.helpers.ClassFileInstaller diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java index 990a5e81e127..6e2cbd54c166 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java @@ -90,11 +90,11 @@ public static void testIncompatibleFeature(String vmOption, String featureName, public String[] vmArgs(RunMode runMode) { if (runMode == RunMode.ASSEMBLY) { if (mode == IncompatibilityMode.MISSING) { - return new String[] {"-Xlog:aot+codecache*=debug"}; + return new String[] {"-Xlog:aot+codecache+exit=debug"}; } else { // UnlockDiagnosticVMOptions must precede vmOption because // some tested CPU feature flags are diagnostic (e.g. UseZba on riscv). - return new String[] {"-XX:+UnlockDiagnosticVMOptions", vmOption, "-Xlog:aot+codecache*=debug"}; + return new String[] {"-XX:+UnlockDiagnosticVMOptions", vmOption, "-Xlog:aot+codecache+exit=debug"}; } } else if (runMode == RunMode.PRODUCTION) { if (mode == IncompatibilityMode.MISSING) { @@ -102,12 +102,12 @@ public String[] vmArgs(RunMode runMode) { vmOption, // Prevent exiting VM on failure "-XX:-AbortVMOnAOTCodeFailure", - "-Xlog:aot+codecache*=debug"}; + "-Xlog:aot+codecache+init=debug"}; } else { return new String[] {"-XX:+UnlockDiagnosticVMOptions", // Prevent exiting VM on failure "-XX:-AbortVMOnAOTCodeFailure", - "-Xlog:aot+codecache*=debug"}; + "-Xlog:aot+codecache+init=debug"}; } } return new String[]{}; diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java index b0d65fe48be1..3d1c3dac962b 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java @@ -26,7 +26,7 @@ * @test * @summary Sanity test of AOT Code Cache with compressed oops configurations * @requires vm.cds.supports.aot.code.caching - * @requires vm.compMode != "Xcomp" + * @requires vm.compMode != "Xcomp" & vm.compMode != "Xint" * @requires vm.bits == 64 * @requires vm.opt.final.UseCompressedOops * @comment The test verifies AOT checks during VM startup and not code generation. @@ -183,7 +183,7 @@ public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception line = list.get(i+2); Matcher m = p.matcher(line); if (!m.find()) { - throw new RuntimeException("Pattern \"" + p + "\" not found in the output"); + throw new RuntimeException("Pattern \"" + p + "\" not found in the output. Got \"" + line + "\""); } aotCacheBase = Long.valueOf(m.group(1), 16); aotCacheShift = Integer.valueOf(m.group(2)); @@ -191,7 +191,7 @@ public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception line = list.get(i+6); m = p.matcher(line); if (!m.find()) { - throw new RuntimeException("Pattern \"" + p + "\" not found in the output"); + throw new RuntimeException("Pattern \"" + p + "\" not found in the output. Got \"" + line + "\""); } currentBase = Long.valueOf(m.group(1), 16); currentShift = Integer.valueOf(m.group(2)); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java index d7ff823734ca..aa857b0167fc 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeFlags.java @@ -27,11 +27,14 @@ * @requires vm.gc != "Z" * @summary Sanity test of combinations of the AOT Code Caching diagnostic flags * @requires vm.cds.supports.aot.code.caching + * @requires vm.compMode != "Xcomp" & vm.compMode != "Xint" + * @comment It runs for long time (hours) with -Xcomp and AOT code caching enabled + * on (virtual) machine with small number of cores * @requires vm.compiler1.enabled & vm.compiler2.enabled * @comment Both C1 and C2 JIT compilers are required because the test verifies * compiler's runtime blobs generation. * @library /test/lib /test/setup_aot - * @build AOTCodeFlags + * @build AOTCodeFlags AOTCodeSimpleTestApp * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar * AOTCodeSimpleTestApp * @run driver/timeout=1500 AOTCodeFlags @@ -41,11 +44,14 @@ * @requires vm.gc.Z * @summary Sanity test of combinations of the AOT Code Caching diagnostic flags * @requires vm.cds.supports.aot.code.caching + * @requires vm.compMode != "Xcomp" & vm.compMode != "Xint" + * @comment It runs for long time (hours) with -Xcomp and AOT code caching enabled + * on (virtual) machine with small number of cores * @requires vm.compiler1.enabled & vm.compiler2.enabled * @comment Both C1 and C2 JIT compilers are required because the test verifies * compiler's runtime blobs generation. * @library /test/lib /test/setup_aot - * @build AOTCodeFlags + * @build AOTCodeFlags AOTCodeSimpleTestApp * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar * AOTCodeSimpleTestApp * @run driver/timeout=1500 AOTCodeFlags Z @@ -55,11 +61,14 @@ * @requires vm.gc.Shenandoah * @summary Sanity test of combinations of the AOT Code Caching diagnostic flags * @requires vm.cds.supports.aot.code.caching + * @requires vm.compMode != "Xcomp" & vm.compMode != "Xint" + * @comment It runs for long time (hours) with -Xcomp and AOT code caching enabled + * on (virtual) machine with small number of cores * @requires vm.compiler1.enabled & vm.compiler2.enabled * @comment Both C1 and C2 JIT compilers are required because the test verifies * compiler's runtime blobs generation. * @library /test/lib /test/setup_aot - * @build AOTCodeFlags + * @build AOTCodeFlags AOTCodeSimpleTestApp * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar * AOTCodeSimpleTestApp * @run driver/timeout=1500 AOTCodeFlags Shenandoah @@ -69,11 +78,14 @@ * @requires vm.gc.Parallel * @summary Sanity test of combinations of the AOT Code Caching diagnostic flags * @requires vm.cds.supports.aot.code.caching + * @requires vm.compMode != "Xcomp" & vm.compMode != "Xint" + * @comment It runs for long time (hours) with -Xcomp and AOT code caching enabled + * on (virtual) machine with small number of cores * @requires vm.compiler1.enabled & vm.compiler2.enabled * @comment Both C1 and C2 JIT compilers are required because the test verifies * compiler's runtime blobs generation. * @library /test/lib /test/setup_aot - * @build AOTCodeFlags + * @build AOTCodeFlags AOTCodeSimpleTestApp * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar * AOTCodeSimpleTestApp * @run driver/timeout=1500 AOTCodeFlags Parallel @@ -90,10 +102,10 @@ public class AOTCodeFlags { private static String gcName = null; public static void main(String... args) throws Exception { Tester t = new Tester(args.length == 0 ? null : args[0]); - // mode bits 0 and 1 encode AOTAdapterCaching and AOTStubCaching settings + // mode bits 0,1,2 encode AOTAdapterCaching, AOTStubCaching and AOTCodeCaching settings // aMode is used for assembly run, pMode for production run - for (int aMode = 0; aMode < 4; aMode++) { - for (int pMode = 0; pMode < 4; pMode++) { + for (int aMode = 0; aMode < 8; aMode++) { + for (int pMode = 0; pMode < 8; pMode++) { t.setTestMode(aMode, pMode); t.run(new String[] {"AOT", "--two-step-training"}); } @@ -118,6 +130,10 @@ boolean isStubCachingOn(int mode) { return (mode & 0x2) != 0; } + boolean isCodeCachingOn(int mode) { + return (mode & 0x4) != 0; + } + public void setTestMode(int aMode, int pMode) { this.aMode = aMode; this.pMode = pMode; @@ -128,6 +144,7 @@ public List getVMArgsForTestMode(int mode) { list.add("-XX:+UnlockDiagnosticVMOptions"); list.add(isAdapterCachingOn(mode) ? "-XX:+AOTAdapterCaching" : "-XX:-AOTAdapterCaching"); list.add(isStubCachingOn(mode) ? "-XX:+AOTStubCaching" : "-XX:-AOTStubCaching"); + list.add(isCodeCachingOn(mode) ? "-XX:+AOTCodeCaching" : "-XX:-AOTCodeCaching"); return list; } @@ -159,6 +176,7 @@ public String[] vmArgs(RunMode runMode) { List args = getGCArgs(); args.addAll(List.of("-Xlog:aot+codecache+init=debug", "-Xlog:aot+codecache+exit=debug", + "-Xlog:aot+codecache+nmethod=info", "-Xlog:aot+codecache+stubs=debug")); // Ensure compilations are finished before the JVM exits. @@ -185,61 +203,84 @@ public String[] appCommandLine(RunMode runMode) { @Override public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { if (runMode == RunMode.ASSEMBLY) { - if (!isAdapterCachingOn(aMode) && !isStubCachingOn(aMode)) { // this is equivalent to completely disable AOT code cache - out.shouldNotMatch("Adapters:\\s+total"); - out.shouldNotMatch("Shared Blobs:\\s+total"); - out.shouldNotMatch("C1 Blobs:\\s+total"); - out.shouldNotMatch("C2 Blobs:\\s+total"); + if (!isAdapterCachingOn(aMode) && !isStubCachingOn(aMode) && !isCodeCachingOn(aMode)) { + // this is equivalent to completely disable AOT code cache + out.shouldNotMatch("Adapter:\\s+total"); + out.shouldNotMatch("SharedBlob:\\s+total"); + out.shouldNotMatch("C1Blob:\\s+total"); + out.shouldNotMatch("C2Blob:\\s+total"); + out.shouldNotMatch("StubGenBlob:\\s+total"); + out.shouldNotMatch("Nmethod:\\s+total"); } else { if (isAdapterCachingOn(aMode)) { - // AOTAdapterCaching is on, non-zero adapters should be stored - out.shouldMatch("Adapters:\\s+total=[1-9][0-9]+"); + // AOTAdapterCaching is on, adapters should be stored + out.shouldMatch("Adapter:\\s+total=[1-9][0-9]+"); } else { // AOTAdapterCaching is off, no adapters should be stored - out.shouldMatch("Adapters:\\s+total=0"); + out.shouldMatch("Adapter:\\s+total=0"); } if (isStubCachingOn(aMode)) { - // AOTStubCaching is on, non-zero stubs should be stored - out.shouldMatch("Shared Blobs:\\s+total=[1-9][0-9]+"); - out.shouldMatch("C1 Blobs:\\s+total=[1-9][0-9]+"); - out.shouldMatch("C2 Blobs:\\s+total=[1-9][0-9]+"); + // AOTStubCaching is on, stubs should be stored + out.shouldMatch("SharedBlob:\\s+total=[1-9][0-9]+"); + out.shouldMatch("C1Blob:\\s+total=[1-9][0-9]+"); + out.shouldMatch("C2Blob:\\s+total=[1-9][0-9]+"); + out.shouldMatch("StubGenBlob:\\s+total=[1-9]+"); } else { // AOTStubCaching is off, no stubs should be stored - out.shouldMatch("Shared Blobs:\\s+total=0"); - out.shouldMatch("C1 Blobs:\\s+total=0"); - out.shouldMatch("C2 Blobs:\\s+total=0"); + out.shouldMatch("SharedBlob:\\s+total=0"); + out.shouldMatch("C1Blob:\\s+total=0"); + out.shouldMatch("C2Blob:\\s+total=0"); + out.shouldMatch("StubGenBlob:\\s+total=0"); + } + if (isCodeCachingOn(aMode)) { + // AOTCodeCaching is on, nmethods should be stored + out.shouldMatch("Nmethod:\\s+total=[1-9][0-9]+"); + } else { + // AOTCodeCaching is off, no nmethods should be stored + out.shouldMatch("Nmethod:\\s+total=0"); } } } else if (runMode == RunMode.PRODUCTION) { - // Irrespective of assembly run mode, if both adapter and stub caching is disabled + // Irrespective of assembly run mode, if all types of code caching is disabled // in production run, then it is equivalent to completely disabling AOT code cache - if (!isAdapterCachingOn(pMode) && !isStubCachingOn(pMode)) { - out.shouldNotMatch("Adapters:\\s+total"); - out.shouldNotMatch("Shared Blobs:\\s+total"); - out.shouldNotMatch("C1 Blobs:\\s+total"); - out.shouldNotMatch("C2 Blobs:\\s+total"); + if (!isAdapterCachingOn(pMode) && !isStubCachingOn(pMode) && !isCodeCachingOn(pMode)) { + out.shouldNotMatch("Adapter:\\s+total"); + out.shouldNotMatch("SharedBlob:\\s+total"); + out.shouldNotMatch("C1Blob:\\s+total"); + out.shouldNotMatch("C2Blob:\\s+total"); + out.shouldNotMatch("StubGenBlob:\\s+total"); + out.shouldNotMatch("Nmethod:\\s+total"); } else { // If AOT code cache is effectively disabled in the assembly run, then production run // would emit empty code cache message. - if (!isAdapterCachingOn(aMode) && !isStubCachingOn(aMode)) { - if (isAdapterCachingOn(pMode) || isStubCachingOn(pMode)) { + if (!isAdapterCachingOn(aMode) && !isStubCachingOn(aMode) && !isCodeCachingOn(aMode)) { + if (isAdapterCachingOn(pMode) || isStubCachingOn(pMode) || isCodeCachingOn(pMode)) { out.shouldMatch("AOT Code Cache is empty"); } } else { if (isAdapterCachingOn(aMode)) { if (isAdapterCachingOn(pMode)) { - out.shouldMatch("Read blob.*kind=Adapter.*"); + out.shouldMatch("Loaded blob.*kind=Adapter.*"); } else { - out.shouldNotMatch("Read blob.*kind=Adapter.*"); + out.shouldNotMatch("Loaded blob.*kind=Adapter.*"); } } if (isStubCachingOn(aMode)) { if (isStubCachingOn(pMode)) { - out.shouldMatch("Read blob.*kind=SharedBlob.*"); - out.shouldMatch("Read blob.*kind=C1Blob.*"); + out.shouldMatch("Loaded blob.*kind=SharedBlob.*"); + out.shouldMatch("Loaded blob.*kind=C1Blob.*"); + out.shouldMatch("Loaded blob.*kind=StubGenBlob.*"); + } else { + out.shouldNotMatch("Loaded blob.*kind=SharedBlob.*"); + out.shouldNotMatch("Loaded blob.*kind=C1Blob.*"); + out.shouldNotMatch("Loaded blob.*kind=StubGenBlob.*"); + } + } + if (isCodeCachingOn(aMode)) { + if (isCodeCachingOn(pMode)) { + out.shouldMatch("Loaded nmethod .*"); } else { - out.shouldNotMatch("Read blob.*kind=SharedBlob.*"); - out.shouldNotMatch("Read blob.*kind=C1Blob.*"); + out.shouldNotMatch("Loaded nmethod .*"); } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTest.java index a27711b716b1..2ff084d2c6ea 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTest.java @@ -189,10 +189,10 @@ public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception } else if (runMode == RunMode.PRODUCTION) { out.shouldMatch("aot,codecache,init.*\\s+Loaded [1-9]\\d+ AOT code entries from AOT Code Cache"); if (!withVerifyOops) { // Adapters are not cached for VerifyOops+Valhalla - out.shouldMatch("aot,codecache,stubs.*\\s+Read blob.*kind=Adapter.*"); + out.shouldMatch("aot,codecache,stubs.*\\s+Loaded blob.*kind=Adapter.*"); } - out.shouldMatch("aot,codecache,stubs.*\\s+Read blob.*kind=SharedBlob.*"); - out.shouldMatch("aot,codecache,stubs.*\\s+Read blob.*kind=C1Blob.*"); + out.shouldMatch("aot,codecache,stubs.*\\s+Loaded blob.*kind=SharedBlob.*"); + out.shouldMatch("aot,codecache,stubs.*\\s+Loaded blob.*kind=C1Blob.*"); } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTestUnknownExternAddress.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTestUnknownExternAddress.java new file mode 100644 index 000000000000..6ee6b8e41688 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeTestUnknownExternAddress.java @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2026, 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 8391718 + * @summary Test AOTAssertOnUnknownExternalAddress flag with unknown external address + * @requires vm.flagless + * @requires vm.debug + * @comment the flag is debug + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler2.enabled + * @library /test/lib /test/setup_aot + * @build ${test.main.class} + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * TestUnknownAddress + * @run driver/timeout=480 ${test.main.class} + */ + +import java.lang.reflect.*; +import sun.misc.*; + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + + +public class AOTCodeTestUnknownExternAddress { + + public static void main(String... args) throws Exception { + String appJar = ClassFileInstaller.getJarPath("app.jar"); + String aotConfigFile = "app.aotconfig"; + String aotCacheFile = "app.aot"; + String appClass = "TestUnknownAddress"; + + ProcessBuilder pb; + OutputAnalyzer out; + + // first make sure we have a valid aotConfigFile + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:CompileCommand=compileonly,TestUnknownAddress::test*", + "-Xcomp", "-XX:-TieredCompilation", + "-Xlog:aot", + "-XX:AOTMode=record", + "-XX:AOTConfiguration=" + aotConfigFile, + "-cp", appJar, appClass); + + out = CDSTestUtils.executeAndLog(pb, "train"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:CompileCommand=compileonly,TestUnknownAddress::test*", + "-Xcomp", "-XX:-TieredCompilation", + "-Xlog:aot+codecache=debug", + "-Xlog:aot+codecache+exit=debug", + "-Xlog:aot+codecache+nmethod", + "-XX:-AOTAssertOnUnknownExternalAddress", + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigFile, + "-XX:AOTCache=" + aotCacheFile, + "-cp", appJar); + + out = CDSTestUtils.executeAndLog(pb, "assemble skip assert"); + out.shouldNotContain("Address 0xffffffffffffffff is missing in AOT Code Cache addresses table"); + out.shouldNotMatch("'TestUnknownAddress\\.test1\\(Z\\)V' AOT.*is skipped: store to AOT Code Cache failed"); + out.shouldMatch("'TestUnknownAddress\\.test1\\(Z\\)V' AOT.*: wrote to AOT Code Cache"); + out.shouldMatch("'TestUnknownAddress\\.test2\\(Z\\)V' AOT.*is skipped: store to AOT Code Cache failed"); + out.shouldMatch("aot,codecache,exit.*Wrote [1-9]\\d* AOT code entries to AOT Code Cache"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:CompileCommand=compileonly,TestUnknownAddress::test*", + "-Xcomp", "-XX:-TieredCompilation", + "-Xlog:aot+codecache+init=debug", + "-XX:AOTMode=on", + "-XX:AOTCache=" + aotCacheFile, + "-cp", appJar, appClass); + + out = CDSTestUtils.executeAndLog(pb, "production"); + out.shouldMatch("aot,codecache,init.*\\s+Loaded [1-9]\\d* AOT code entries from AOT Code Cache"); + out.shouldHaveExitValue(0); + + // Assembly run with assert + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-XX:CompileCommand=compileonly,TestUnknownAddress::test*", + "-Xcomp", "-XX:-TieredCompilation", + "-XX:-CreateCoredumpOnCrash", + "-Xlog:aot+codecache=debug", + "-Xlog:aot+codecache+exit=debug", + "-Xlog:aot+codecache+nmethod", + "-XX:+AOTAssertOnUnknownExternalAddress", + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigFile, + "-XX:AOTCache=" + aotCacheFile, + "-cp", appJar); + + out = ProcessTools.executeProcess(pb); + out.shouldContain("for is missing in AOT Code Cache addresses table"); + out.shouldNotHaveExitValue(0); + } +} + +class TestUnknownAddress { + private static Unsafe unsafe; + private static final long UNKNOWN_ADDRESS = 0x1234_5678_9000L; + private static final long MINUS_1_ADDRESS = -1L; + + static { + try { + Field field = Unsafe.class.getDeclaredField("theUnsafe"); + field.setAccessible(true); + unsafe = (Unsafe)field.get(null); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public static void test1(boolean b) { + if (b) { + unsafe.putLong(MINUS_1_ADDRESS, 42); + } + } + + public static void test2(boolean b) { + if (b) { + unsafe.putLong(UNKNOWN_ADDRESS, 42); + } + } + + public static void main(String[] args) { + test1(false); + test2(false); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestAOTCodeCounters.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestAOTCodeCounters.java new file mode 100644 index 000000000000..0aaa8a66ddf9 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestAOTCodeCounters.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2026, 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 + * @summary Test AOT code invocation counters in C2 compiled AOT code + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler2.enabled + * @comment C2 JIT compiler is required because the test verifies + * compiled code generation. + * @library /test/lib /test/setup_aot + * @build ${test.main.class} AOTCodeSimpleTestApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * AOTCodeSimpleTestApp + * @run driver/timeout=480 ${test.main.class} + */ + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Random; + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.Utils; + +public class TestAOTCodeCounters { + private static final Random RANDOM = Utils.getRandomInstance(); + + // Test default (Base=100. Scale=1.) and limit values. + static String randomBase = String.valueOf(RANDOM.nextDouble(1.0, 10000.0)); + static String randomScale = String.valueOf(RANDOM.nextDouble(0.001, 1000.0)); + static String[][] flags = { + {"-XX:AOTCodeInvokeBase=1.0", "-XX:AOTCodeInvokeScale=0.001"}, + {"-XX:AOTCodeInvokeBase=1.0", "-XX:AOTCodeInvokeScale=1.0"}, + {"-XX:AOTCodeInvokeBase=1.0", "-XX:AOTCodeInvokeScale=1000.0"}, + {"-XX:AOTCodeInvokeBase=100.0", "-XX:AOTCodeInvokeScale=0.001"}, + {"-XX:AOTCodeInvokeBase=100.0", "-XX:AOTCodeInvokeScale=1.0"}, + {"-XX:AOTCodeInvokeBase=100.0", "-XX:AOTCodeInvokeScale=1000.0"}, + {"-XX:AOTCodeInvokeBase=10000.0", "-XX:AOTCodeInvokeScale=0.001"}, + {"-XX:AOTCodeInvokeBase=10000.0", "-XX:AOTCodeInvokeScale=1.0"}, + {"-XX:AOTCodeInvokeBase=10000.0", "-XX:AOTCodeInvokeScale=1000.0"}, + {"-XX:AOTCodeInvokeBase=" + randomBase, "-XX:AOTCodeInvokeScale=" + randomScale} + }; + + public static void main(String... args) throws Exception { + System.out.println("Random: -XX:AOTCodeInvokeBase=" + randomBase + " -XX:AOTCodeInvokeScale=" + randomScale); + for (int i = 0; i < flags.length; i++) { + Tester t = new Tester(flags[i]); + t.run(new String[] {"AOT", "--two-step-training"}); + } + } + + static class Tester extends CDSAppTester { + private String[] Counterflags; + + public Tester(String[] flags) { + super("TestAOTCodeCounters"); + Counterflags = flags; + } + + @Override + public String classpath(RunMode runMode) { + return "app.jar"; + } + + @Override + public String[] vmArgs(RunMode runMode) { + List args = new ArrayList(); + + // Ensure compilations are finished before the JVM exits. + args.add("-Xbatch"); + + // Add flags for logs + args.addAll(List.of("-Xlog:aot+codecache+init=debug", + "-Xlog:aot+codecache+nmethod=info", + "-Xlog:aot+codecache+exit=debug")); + // Add diagnostic flags + args.addAll(List.of("-XX:+UnlockDiagnosticVMOptions", + "-XX:+UseAOTCodeCounters", + "-XX:+AbortVMOnAOTCodeFailure")); + // Add feature flag + args.addAll(Arrays.asList(Counterflags)); + return args.toArray(new String[args.size()]); + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { "AOTCodeSimpleTestApp" }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { + if (runMode == RunMode.ASSEMBLY) { + out.shouldMatch("aot,codecache,exit.*\\s+AOT code cache size: [1-9]\\d+ bytes"); + out.shouldMatch("Nmethod:\\s+total=[1-9][0-9]+"); + } else if (runMode == RunMode.PRODUCTION) { + out.shouldMatch("aot,codecache,init.*\\s+Loaded [1-9]\\d+ AOT code entries from AOT Code Cache"); + out.shouldMatch("Loaded nmethod .*"); + } + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestAOTCodeFeatures.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestAOTCodeFeatures.java new file mode 100644 index 000000000000..00a75baa157a --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestAOTCodeFeatures.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2026, 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 + * @summary Sanity test AOTCodeCache flags + * @requires vm.cds.supports.aot.code.caching + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * compiled code generation. + * @library /test/lib /test/setup_aot + * @build TestAOTCodeFeatures JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=480 ${test.main.class} + */ + +import java.util.ArrayList; +import java.util.List; + +import jdk.test.lib.cds.CDSAppTester; +import jdk.test.lib.process.OutputAnalyzer; + +public class TestAOTCodeFeatures { + + // Too long to test both, default and opposite, values. + // Only test opposite. + static String[] flags = { + "-XX:-AOTCompileEagerly", + "-XX:ClassInitBarrierMode=0", + "-XX:-UseAOTCodeCounters", + "-XX:-PreloadReduceTraps", + "-XX:+AOTPreloadBlocking", + "-XX:AOTCodePreloadStart=2G", + "-XX:AOTCodePreloadStop=0" + }; + + public static void main(String... args) throws Exception { + for (int i = 0; i < flags.length; i++) { + Tester t = new Tester(flags[i]); + t.run(new String[] {"AOT", "--two-step-training"}); + } + } + + static class Tester extends CDSAppTester { + private String flagName; + + public Tester(String name) { + super("TestAOTCodeFeatures"); + flagName = name; + } + + @Override + public String classpath(RunMode runMode) { + return "app.jar"; + } + + @Override + public String[] vmArgs(RunMode runMode) { + List args = new ArrayList(); + // Add flags for logs + args.addAll(List.of("-Xlog:aot+codecache+init=debug", + "-Xlog:aot+codecache+exit=debug")); + // Add diagnostic flags + args.addAll(List.of("-XX:+UnlockDiagnosticVMOptions", + "-XX:+AbortVMOnAOTCodeFailure")); + // Add feature flag + args.add(flagName); + return args.toArray(new String[args.size()]); + } + + @Override + public String[] appCommandLine(RunMode runMode) { + return new String[] { "JavacBenchApp", "1" }; + } + + @Override + public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { + if (runMode == RunMode.ASSEMBLY) { + out.shouldMatch("aot,codecache,exit.*\\s+AOT code cache size: [1-9]\\d+ bytes"); + } else if (runMode == RunMode.PRODUCTION) { + out.shouldMatch("aot,codecache,init.*\\s+Loaded [1-9]\\d+ AOT code entries from AOT Code Cache"); + } + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestDisableAOTCode.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestDisableAOTCode.java new file mode 100644 index 000000000000..cc295b7231c9 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestDisableAOTCode.java @@ -0,0 +1,219 @@ +/* + * Copyright (c) 2026, 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 + * @summary Sanity test of the diagnostic flag -XX:DisableAOTCode=n + * @requires vm.cds.supports.aot.code.caching + * @requires vm.flagless + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * all AOT code tiers generation (except tier 3). + * @library /test/lib /test/setup_aot + * @build TestDisableAOTCode JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=480 TestDisableAOTCode + */ + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class TestDisableAOTCode { + + public static void main(String... args) throws Exception { + String appJar = ClassFileInstaller.getJarPath("app.jar"); + String aotConfigFile = "app.aotconfig"; + String aotCacheFile = "app.aot"; + String appClass = "JavacBenchApp"; + String appArgs = "1"; + + ProcessBuilder pb; + OutputAnalyzer out; + + // first make sure we have a valid aotConfigFile + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot", + "-XX:AOTMode=record", + "-XX:AOTConfiguration=" + aotConfigFile, + "-cp", appJar, appClass, appArgs); + + out = CDSTestUtils.executeAndLog(pb, "train"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+exit", + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigFile, + "-XX:AOTCache=" + aotCacheFile, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:DisableAOTCode=1", + "-cp", appJar); + + out = CDSTestUtils.executeAndLog(pb, "assemble_no_AOT_T1"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 1: total=0"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 2:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 3: total=0"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 4:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 5:.*"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+exit", + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigFile, + "-XX:AOTCache=" + aotCacheFile, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:DisableAOTCode=10000", + "-cp", appJar); + + out = CDSTestUtils.executeAndLog(pb, "assemble_no_AOT_T5"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 1:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 2:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 3: total=0"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 4:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 5: total=0"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+exit", + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigFile, + "-XX:AOTCache=" + aotCacheFile, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:DisableAOTCode=11111", + "-cp", appJar); + + out = CDSTestUtils.executeAndLog(pb, "assemble_no_AOT_all"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 1: total=0"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 2: total=0"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 3: total=0"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 4: total=0"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 5: total=0"); + out.shouldHaveExitValue(0); + + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+exit", + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigFile, + "-XX:AOTCache=" + aotCacheFile, + "-cp", appJar); + + out = CDSTestUtils.executeAndLog(pb, "assemble_default"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 1:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 2:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 3: total=0"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 4:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 5:.*"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+init", + "-XX:AOTCache=" + aotCacheFile, + "-XX:+CITime", + "-cp", appJar, appClass, appArgs); + + out = CDSTestUtils.executeAndLog(pb, "production_default"); + out.shouldMatch(" AOT Code T1.*"); + out.shouldMatch(" AOT Code T2.*"); + out.shouldMatch(" AOT Code T4.*"); + out.shouldMatch(" AOT Code T5.*"); + // Tier 3 AOT code generation is not implemented + out.shouldNotMatch("\\s+AOT Code T3.*"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+init", + "-XX:AOTCache=" + aotCacheFile, + "-XX:+CITime", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:DisableAOTCode=1", + "-cp", appJar, appClass, appArgs); + + out = CDSTestUtils.executeAndLog(pb, "production_no_AOT_T1"); + out.shouldNotMatch(" AOT Code T1.*"); + out.shouldMatch(" AOT Code T2.*"); + out.shouldMatch(" AOT Code T4.*"); + out.shouldMatch(" AOT Code T5.*"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+init", + "-XX:AOTCache=" + aotCacheFile, + "-XX:+CITime", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:DisableAOTCode=10000", + "-cp", appJar, appClass, appArgs); + + out = CDSTestUtils.executeAndLog(pb, "production_no_AOT_T5"); + out.shouldMatch(" AOT Code T1.*"); + out.shouldMatch(" AOT Code T2.*"); + out.shouldMatch(" AOT Code T4.*"); + out.shouldNotMatch(" AOT Code T5.*"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+init", + "-XX:AOTCache=" + aotCacheFile, + "-XX:+CITime", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:DisableAOTCode=11111", + "-cp", appJar, appClass, appArgs); + + out = CDSTestUtils.executeAndLog(pb, "production_no_AOT_all"); + out.shouldNotMatch(" AOT Code T1.*"); + out.shouldNotMatch(" AOT Code T2.*"); + out.shouldNotMatch(" AOT Code T4.*"); + out.shouldNotMatch(" AOT Code T5.*"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+init", + "-XX:AOTCache=" + aotCacheFile, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:DisableAOTCode=15", + "-cp", appJar, appClass, appArgs); + + out = CDSTestUtils.executeAndLog(pb, "production_wrong_value"); + out.shouldContain("Improperly specified VM option 'DisableAOTCode=15'"); + out.shouldHaveExitValue(1); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+init", + "-XX:AOTCache=" + aotCacheFile, + "-XX:+UnlockDiagnosticVMOptions", + "-XX:DisableAOTCode=111111", + "-cp", appJar, appClass, appArgs); + + out = CDSTestUtils.executeAndLog(pb, "production_wrong_digits"); + out.shouldContain("Improperly specified VM option 'DisableAOTCode=111111'"); + out.shouldHaveExitValue(1); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestVerifyAOTCode.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestVerifyAOTCode.java new file mode 100644 index 000000000000..3c88ca3651d2 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/TestVerifyAOTCode.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2026, 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 + * @summary Sanity test of the diagnostic flag -XX:+VerifyAOTCode + * @requires vm.cds.supports.aot.code.caching + * @requires vm.flagless + * @requires vm.compiler1.enabled & vm.compiler2.enabled + * @comment Both C1 and C2 JIT compilers are required because the test verifies + * all AOT code tiers generation (except tier 3). + * @library /test/lib /test/setup_aot + * @build TestVerifyAOTCode JavacBenchApp + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar + * JavacBenchApp + * JavacBenchApp$ClassFile + * JavacBenchApp$FileManager + * JavacBenchApp$SourceFile + * @run driver/timeout=480 TestVerifyAOTCode + */ + +import jdk.test.lib.cds.CDSTestUtils; +import jdk.test.lib.helpers.ClassFileInstaller; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class TestVerifyAOTCode { + + public static void main(String... args) throws Exception { + String appJar = ClassFileInstaller.getJarPath("app.jar"); + String aotConfigFile = "app.aotconfig"; + String aotCacheFile = "app.aot"; + String appClass = "JavacBenchApp"; + String appArgs = "10"; + + ProcessBuilder pb; + OutputAnalyzer out; + + // first make sure we have a valid aotConfigFile + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot", + "-XX:AOTMode=record", + "-XX:AOTConfiguration=" + aotConfigFile, + "-cp", appJar, appClass, appArgs); + + out = CDSTestUtils.executeAndLog(pb, "train"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+exit", + "-XX:AOTMode=create", + "-XX:AOTConfiguration=" + aotConfigFile, + "-XX:AOTCache=" + aotCacheFile, + "-cp", appJar); + + out = CDSTestUtils.executeAndLog(pb, "assemble"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 1:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 2:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 3:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 4:.*"); + out.shouldMatch("aot,codecache,exit.*\\s+Tier 5:.*"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+init", + "-Xlog:aot+codecache+nmethod", + "-XX:AOTCache=" + aotCacheFile, + "-XX:+CITime", + "-cp", appJar, appClass, appArgs); + + out = CDSTestUtils.executeAndLog(pb, "production_default"); + out.shouldMatch("Loaded nmethod from AOT Code Cache"); + out.shouldMatch(" AOT Code T1.*"); + out.shouldMatch(" AOT Code T2.*"); + out.shouldMatch(" AOT Code T4.*"); + out.shouldMatch(" AOT Code T5.*"); + // Tier 3 AOT code generation is not implemented + out.shouldNotMatch("\\s+AOT Code T3.*"); + out.shouldHaveExitValue(0); + + pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot+codecache+init", + "-Xlog:aot+codecache+nmethod", + "-XX:AOTCache=" + aotCacheFile, + "-XX:+CITime", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+VerifyAOTCode", + "-cp", appJar, appClass, appArgs); + + out = CDSTestUtils.executeAndLog(pb, "production_VerifyAOTCode"); + out.shouldMatch("Verified nmethod from AOT Code Cache"); + out.shouldNotMatch("Loaded nmethod from AOT Code Cache"); + out.shouldMatch(" AOT Code T1.*"); + out.shouldMatch(" AOT Code T2.*"); + out.shouldMatch(" AOT Code T4.*"); + out.shouldMatch(" AOT Code T5.*"); + out.shouldHaveExitValue(0); + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java index fc24f341ff36..9564e619ecd4 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotFlags/AOTFlags.java @@ -25,7 +25,7 @@ /* * @test * @summary "AOT" aliases for traditional CDS command-line options - * @requires vm.cds + * @requires vm.cds.supports.aot.code.caching * @requires vm.flagless * @library /test/lib /test/hotspot/jtreg/runtime/cds/appcds/test-classes * @build Hello @@ -52,6 +52,11 @@ public static void main(String[] args) throws Exception { } static void positiveTests() throws Exception { + String hasTrainingDataPattern = "MethodTrainingData *= *[1-9]"; + String hasAOTCodePattern = "Shared file region .ac. .: *[1-9]"; + String noAOTCodePattern = "Shared file region .ac. .: *0"; + String hasMappedAOTCodePattern = "Mapped [0-9]+ bytes at address 0x[0-9a-f]+ from AOT Code Cache"; + //---------------------------------------------------------------------- printTestCase("Training Run"); ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( @@ -63,6 +68,8 @@ static void positiveTests() throws Exception { OutputAnalyzer out = CDSTestUtils.executeAndLog(pb, "train"); out.shouldContain("Hello World"); out.shouldContain("AOTConfiguration recorded: " + aotConfigFile); + out.shouldMatch(hasTrainingDataPattern); + out.shouldMatch(noAOTCodePattern); out.shouldHaveExitValue(0); //---------------------------------------------------------------------- @@ -78,6 +85,8 @@ static void positiveTests() throws Exception { out = CDSTestUtils.executeAndLog(pb, "asm"); out.shouldContain("AOTCache creation is complete"); out.shouldMatch("hello[.]aot"); + out.shouldMatch(hasTrainingDataPattern); + out.shouldMatch(hasAOTCodePattern); out.shouldHaveExitValue(0); //---------------------------------------------------------------------- @@ -85,11 +94,13 @@ static void positiveTests() throws Exception { pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTCache=" + aotCacheFile, "-Xlog:aot", + "-Xlog:aot+codecache*", "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod"); out.shouldContain("Using AOT-linked classes: true (static archive: has aot-linked classes)"); out.shouldContain("Opened AOT cache hello.aot."); out.shouldContain("Hello World"); + out.shouldMatch(hasMappedAOTCodePattern); out.shouldHaveExitValue(0); //---------------------------------------------------------------------- @@ -143,7 +154,7 @@ static void positiveTests() throws Exception { "-XX:-AOTClassLinking", "-XX:AOTConfiguration=" + aotConfigFile, "-XX:AOTCache=" + aotCacheFile, - "-Xlog:aot", + "-Xlog:aot=debug", "-XX:+UnlockDiagnosticVMOptions", "-XX:+AOTCompatibleOopCompression", // avoid production run failure due to incompatible CompressedOops::base "-cp", appJar); @@ -151,6 +162,8 @@ static void positiveTests() throws Exception { out.shouldContain("AOTClassLinking is updated to true (the same as when AOT configuration file"); out.shouldContain("AOTCache creation is complete"); out.shouldMatch("hello[.]aot"); + out.shouldMatch(hasTrainingDataPattern); + out.shouldMatch(hasAOTCodePattern); out.shouldHaveExitValue(0); //---------------------------------------------------------------------- @@ -158,11 +171,13 @@ static void positiveTests() throws Exception { pb = ProcessTools.createLimitedTestJavaProcessBuilder( "-XX:AOTCache=" + aotCacheFile, "-Xlog:aot", + "-Xlog:aot+codecache*", "-cp", appJar, helloClass); out = CDSTestUtils.executeAndLog(pb, "prod"); out.shouldContain("Using AOT-linked classes: true"); out.shouldContain("Opened AOT cache hello.aot."); out.shouldContain("Hello World"); + out.shouldMatch(hasMappedAOTCodePattern); out.shouldHaveExitValue(0); //---------------------------------------------------------------------- diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java b/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java index 4ad42cb715b6..7564f8880ecc 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotProfile/AOTProfileFlags.java @@ -74,6 +74,7 @@ static void trainAndRun(String testName, String trainingFlags, String production // first make sure we have a valid aotConfigFile with default value of TypeProfileLevel pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot", "-XX:AOTMode=record", "-XX:AOTConfiguration=" + aotConfigFile, "-XX:+UnlockExperimentalVMOptions", @@ -84,6 +85,7 @@ static void trainAndRun(String testName, String trainingFlags, String production out.shouldHaveExitValue(0); pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot", "-XX:AOTMode=create", "-XX:AOTConfiguration=" + aotConfigFile, "-XX:AOTCache=" + aotCacheFile, @@ -95,6 +97,7 @@ static void trainAndRun(String testName, String trainingFlags, String production out.shouldHaveExitValue(0); pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot", "-XX:AOTCache=" + aotCacheFile, "-XX:+UnlockExperimentalVMOptions", trainingFlags, @@ -105,6 +108,7 @@ static void trainAndRun(String testName, String trainingFlags, String production out.shouldHaveExitValue(0); pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xlog:aot", "-XX:AOTCache=" + aotCacheFile, "-XX:+UnlockExperimentalVMOptions", productionFlags, diff --git a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java index 7eecf5278505..71507fa6e705 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/gc/HeapDumpParallelTest.java @@ -25,14 +25,12 @@ import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import jdk.test.lib.Asserts; import jdk.test.lib.JDKToolLauncher; -import jdk.test.lib.Utils; import jdk.test.lib.apps.LingeredApp; import jdk.test.lib.dcmd.PidJcmdExecutor; import jdk.test.lib.process.OutputAnalyzer; @@ -42,7 +40,7 @@ /** * @test - * @bug 8306441 8319053 + * @bug 8306441 8319053 8384612 * @summary Verify the integrity of generated heap dump and capability of parallel dump * @library /test/lib * @run main HeapDumpParallelTest @@ -57,12 +55,13 @@ private static void checkAndVerify(OutputAnalyzer dcmdOut, LingeredApp app, File dcmdOut.shouldContain("Heap dump file created"); OutputAnalyzer appOut = new OutputAnalyzer(app.getProcessStdout()); appOut.shouldMatch("\\[heapdump *\\]"); - String opts = Arrays.asList(Utils.getTestJavaOpts()).toString(); - if (opts.contains("-XX:+UseSerialGC") || opts.contains("-XX:+UseEpsilonGC")) { - System.out.println("UseSerialGC detected."); + // Check the target VM's selected GC, including ergonomic selection. + appOut.shouldMatch("\\[gc *\\] Using "); + if (appOut.getStdout().contains("Using Serial") || appOut.getStdout().contains("Using Epsilon")) { + System.out.println("Serial or Epsilon GC detected."); expectSerial = true; } - if (!expectSerial && Runtime.getRuntime().availableProcessors() > 1) { + if (!expectSerial) { appOut.shouldContain("Dump heap objects in parallel"); appOut.shouldContain("Merge heap files complete"); } else { @@ -86,7 +85,7 @@ private static void checkAndVerify(OutputAnalyzer dcmdOut, LingeredApp app, File private static LingeredApp launchApp() throws IOException { LingeredApp theApp = new LingeredApp(); - LingeredApp.startApp(theApp, "-Xlog:heapdump", "-Xmx512m", + LingeredApp.startApp(theApp, "-Xlog:gc,heapdump", "-Xmx512m", "-XX:-UseDynamicNumberOfGCThreads", "-XX:ParallelGCThreads=2"); return theApp; @@ -118,7 +117,7 @@ public static void main(String[] args) throws Exception { test(heapDumpFile, "-parallel=" + Integer.MAX_VALUE, false); // Expect parallel dump - test(heapDumpFile, "-gz=9 -overwrite -parallel=" + Runtime.getRuntime().availableProcessors(), false); + test(heapDumpFile, "-gz=9 -overwrite -parallel=" + Math.max(Runtime.getRuntime().availableProcessors(), 2), false); } finally { theApp.stopApp(); } diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/Heapwalking/FlatClassFilterTest.java b/test/hotspot/jtreg/serviceability/jvmti/valhalla/Heapwalking/FlatClassFilterTest.java new file mode 100644 index 000000000000..7118c09226f9 --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/Heapwalking/FlatClassFilterTest.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2026, 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 id=default + * @bug 8389460 + * @summary JVMTI IterateThroughHeap class filter should not skip flattened value objects + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.value + * java.base/jdk.internal.vm.annotation + * @requires vm.jvmti + * @enablePreview + * @run main/othervm/native -agentlib:FlatClassFilterTest + * -XX:+UnlockDiagnosticVMOptions + * -XX:+UnlockExperimentalVMOptions + * -XX:+UseArrayFlattening + * -XX:+UseFieldFlattening + * -XX:+UseNullFreeAtomicValueFlattening + * -XX:+UseNullableAtomicValueFlattening + * FlatClassFilterTest + */ + +/* + * @test id=class_untagged + * @bug 8389460 + * @summary JVMTI IterateThroughHeap class filter should not skip flattened value objects + * @modules java.base/jdk.internal.misc + * java.base/jdk.internal.value + * java.base/jdk.internal.vm.annotation + * @requires vm.jvmti + * @enablePreview + * @run main/othervm/native -agentlib:FlatClassFilterTest=heap_filter_class_untagged + * -XX:+UnlockDiagnosticVMOptions + * -XX:+UnlockExperimentalVMOptions + * -XX:+UseArrayFlattening + * -XX:+UseFieldFlattening + * -XX:+UseNullFreeAtomicValueFlattening + * -XX:+UseNullableAtomicValueFlattening + * FlatClassFilterTest + */ + +import java.lang.ref.Reference; +import jdk.internal.misc.Unsafe; +import jdk.internal.value.ValueClass; +import jdk.internal.vm.annotation.NullRestricted; + +public class FlatClassFilterTest { + private static void log(String msg) { + System.out.println(msg); + System.out.flush(); + } + + static Value[] array; + static Value heap = new Value(999); + + static value class Value { + int x; + Value(int x) { this.x = x; } + } + + static value class ValueHolder { + @NullRestricted + public Value v1; + + public Value vn; + public Value[] v_arr; + + public ValueHolder(int seed) throws Exception { + v1 = new Value(seed); + vn = null; + v_arr = createValueArray(seed); + } + } + + static Value[] createValueArray(int seed) throws Exception { + Value[] arr = (Value[])ValueClass.newNullableAtomicArray(Value.class, 5); + for (int i = 0; i < arr.length; i++) { + arr[i] = (i == 2 ? null : new Value(seed + 10 + i)); + } + return arr; + } + + static final long CLASS_TAG = 71; + static final Unsafe U = Unsafe.getUnsafe(); + + static native int count(Class filter, Class taggedClass, long classTag); + + public static void main(String[] args) throws Exception { + System.loadLibrary("FlatClassFilterTest"); + log("FlatClassFilterTest: Started"); + + ValueHolder holder = new ValueHolder(10); + array = createValueArray(100); + + // Use Unsafe because there is no non-unsafe API to check the field flatness. + boolean isFlatV1 = U.isFlatField(ValueHolder.class.getDeclaredField("v1")); + boolean isFlatArr = ValueClass.isFlatArray(array); + int all = count(null, Value.class, CLASS_TAG); + int filtered = count(Value.class, Value.class, CLASS_TAG); + + log("v1 is flat: " + isFlatV1); + log("array is flat: " + isFlatArr); + log("all: " + all); + log("filtered: " + filtered); + + if (!isFlatV1) { + throw new AssertionError("The field holder.v1 is expected to be flat"); + } + if (!isFlatArr) { + throw new AssertionError("The array is expected to be flat"); + } + if (filtered != all) { + throw new AssertionError("V.class filter skipped flat V[] element"); + } + Reference.reachabilityFence(holder); + log("FlatClassFilterTest: PASSED"); + } +} diff --git a/test/hotspot/jtreg/serviceability/jvmti/valhalla/Heapwalking/libFlatClassFilterTest.cpp b/test/hotspot/jtreg/serviceability/jvmti/valhalla/Heapwalking/libFlatClassFilterTest.cpp new file mode 100644 index 000000000000..105ccc890cad --- /dev/null +++ b/test/hotspot/jtreg/serviceability/jvmti/valhalla/Heapwalking/libFlatClassFilterTest.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2026, 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. + */ + +#include +#include "jvmti_common.hpp" + +extern "C" { + +static jvmtiEnv* jvmti = nullptr; +static jlong wanted_tag = 0; +static jint object_count = 0; +static jint heap_filter = 0; + +static jint JNICALL +heap_iteration(jlong class_tag, jlong size, jlong* tag_ptr, jint length, void* user_data) { + if (class_tag == wanted_tag) { + object_count++; + } + return 0; +} + +JNIEXPORT jint JNICALL +Java_FlatClassFilterTest_count(JNIEnv* jni, jclass ignored, jclass class_filter, + jclass tagged_class, jlong class_tag) { + jvmtiError err = jvmti->SetTag(tagged_class, class_tag); + check_jvmti_status(jni, err, "SetTag"); + + jvmtiHeapCallbacks callbacks; + memset(&callbacks, 0, sizeof(callbacks)); + + wanted_tag = class_tag; + object_count = 0; + callbacks.heap_iteration_callback = heap_iteration; + + err = jvmti->IterateThroughHeap(heap_filter, class_filter, &callbacks, nullptr); + check_jvmti_status(jni, err, "IterateThroughHeap"); + + return object_count; +} + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM* vm, char* options, void* reserved) { + if (vm->GetEnv(reinterpret_cast(&jvmti), JVMTI_VERSION_1_2) != JNI_OK) { + LOG("Agent_OnLoad: Failed: Could not initialize JVMTI\n"); + return JNI_ERR; + } + if (options != nullptr) { + if (strcmp(options, "heap_filter_class_untagged") == 0) { + heap_filter = JVMTI_HEAP_FILTER_CLASS_UNTAGGED; + } else { + LOG("Agent_OnLoad: Failed: unrecognized agent option"); + return JNI_ERR; + } + } + jvmtiCapabilities caps; + memset(&caps, 0, sizeof(caps)); + caps.can_tag_objects = 1; + + jvmtiError err = jvmti->AddCapabilities(&caps); + check_jvmti_error(err, "AddCapabilities"); + + return JNI_OK; +} + +} // extern "C" + diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects003/referringObjects003.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects003/referringObjects003.java index a1a191d00711..529649c516b6 100644 --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects003/referringObjects003.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/ObjectReference/referringObjects/referringObjects003/referringObjects003.java @@ -133,6 +133,17 @@ public void checkThreadReferrersCount(List objectReferences, in } } + private void logLeftover(ObjectReference objectReference) { + try { + log.complain(objectReference.toString()); + for (ObjectReference referrer : objectReference.referringObjects(0)) { + log.complain(" referred from " + referrer); + } + } catch (ObjectCollectedException e) { + log.complain("object " + objectReference.uniqueID() + " was collected before it could be described"); + } + } + public void doTest() { int threadCount = 15; @@ -178,35 +189,40 @@ public void doTest() { if (!isDebuggeeReady()) return; - // Force the test ThreadGroup to be collected. The only reference to it is a weak - // reference from the parent ThreadGroup. - forceGC(); + // The joined threads still hold the group in holder.group and the VM + // releases its handles to them a little later on another thread. The + // retry gives that release time to happen. Each forceGC has to stay a + // real full collection, a cheaper one here would not clear the group + // and the loop would just run out of retries. + for (int i = 0; i < 5; i++) { + forceGC(); + threadGroups = HeapwalkingDebugger.filterObjectReferrence(threadGroupsToFilter, HeapwalkingDebugger + .getObjectReferences("java.lang.ThreadGroup", vm)); + threads = HeapwalkingDebugger.filterObjectReferrence(threadsToFilter, HeapwalkingDebugger + .getObjectReferences("java.lang.Thread", vm)); + if (threadGroups.isEmpty() && threads.isEmpty()) { + break; + } + } checkDebugeeAnswer_instances("java.lang.ThreadGroup", threadGroupsToFilter.size()); checkDebugeeAnswer_instances("java.lang.Thread", threadsToFilter.size()); - threadGroups = HeapwalkingDebugger.filterObjectReferrence(threadGroupsToFilter, HeapwalkingDebugger - .getObjectReferences("java.lang.ThreadGroup", vm)); - if (threadGroups.size() != 0) { setSuccess(false); log.complain("All test threads groups should be removed"); log.complain("Unexpected threads groups:"); for (ObjectReference objectReference : threadGroups) { - log.complain(objectReference.toString()); + logLeftover(objectReference); } } - threads = HeapwalkingDebugger.filterObjectReferrence(threadsToFilter, HeapwalkingDebugger.getObjectReferences( - "java.lang.Thread", - vm)); - if (threads.size() != 0) { setSuccess(false); log.complain("All test threads should be removed"); log.complain("Unexpected threads:"); for (ObjectReference objectReference : threads) { - log.complain(objectReference.toString()); + logLeftover(objectReference); } } } diff --git a/test/jdk/ProblemList-AotJdk.txt b/test/jdk/ProblemList-AotJdk.txt index 37d7a80fa560..49d28c049140 100644 --- a/test/jdk/ProblemList-AotJdk.txt +++ b/test/jdk/ProblemList-AotJdk.txt @@ -44,6 +44,15 @@ java/lang/invoke/DumpMethodHandleInternals.java 0000000 generic- # this message will not be printed in the production run. java/util/Locale/UseOldISOCodesTest.java 0000000 generic-all +# These vector tests hit MemLimit during C2 compilation on Aarch64 +jdk/incubator/vector/Vector128ConversionTests.java 8337281 linux-aarch64,macosx-aarch64 +jdk/incubator/vector/Vector256ConversionTests.java 8337281 linux-aarch64,macosx-aarch64 +jdk/incubator/vector/Vector512ConversionTests.java 8337281 linux-aarch64,macosx-aarch64 +jdk/incubator/vector/Vector64ConversionTests.java#id0 8337281 linux-aarch64,macosx-aarch64 +jdk/incubator/vector/VectorMaxConversionTests.java#id0 8337281 linux-aarch64,macosx-aarch64 + +java/util/concurrent/locks/Lock/OOMEInAQS.java 8393490 generic-all + ############################################################################# # Preview project specific failures go here at the end of the file. diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index bf8e319f9db0..a9ed48c86434 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -129,6 +129,7 @@ java/awt/dnd/MissingDragExitEventTest/MissingDragExitEventTest.java 8288839 wind java/awt/dnd/DragExitBeforeDropTest.java 8242805 macosx-all java/awt/dnd/DragThresholdTest.java 8076299 macosx-all java/awt/dnd/CustomDragCursorTest.java 8242805 macosx-all +java/awt/dnd/Button2DragTest/Button2DragTest.java 8393735 macosx-aarch64 java/awt/Focus/ClearLwQueueBreakTest/ClearLwQueueBreakTest.java 8198618 macosx-all java/awt/Focus/ConsumeNextKeyTypedOnModalShowTest/ConsumeNextKeyTypedOnModalShowTest.java 6986252 macosx-all java/awt/Focus/MouseClickRequestFocusRaceTest/MouseClickRequestFocusRaceTest.java 8194753 linux-all,macosx-all diff --git a/test/jdk/java/foreign/TestBufferStack.java b/test/jdk/java/foreign/TestBufferStack.java deleted file mode 100644 index 6873cb6415e5..000000000000 --- a/test/jdk/java/foreign/TestBufferStack.java +++ /dev/null @@ -1,294 +0,0 @@ -/* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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/jdk.internal.foreign - * @build NativeTestHelper TestBufferStack - * @run junit/othervm --enable-native-access=ALL-UNNAMED TestBufferStack - */ - -import jdk.internal.foreign.BufferStack; -import org.junit.jupiter.api.Test; - -import java.lang.foreign.Arena; -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.SegmentAllocator; -import java.lang.invoke.MethodHandle; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.atomic.AtomicReference; -import java.util.function.Consumer; - -import jdk.test.lib.thread.VThreadRunner; - -import static java.lang.foreign.MemoryLayout.structLayout; -import static java.lang.foreign.ValueLayout.*; -import static org.junit.jupiter.api.Assertions.*; - -final class TestBufferStack extends NativeTestHelper { - - private static final long POOL_SIZE = 64; - private static final long SMALL_ALLOC_SIZE = JAVA_LONG.byteSize(); - - @Test - void invariants() { - var exBS = assertThrows(IllegalArgumentException.class, () -> BufferStack.of(-1, 1)); - assertEquals("Negative byteSize: -1", exBS.getMessage()); - var exBA = assertThrows(IllegalArgumentException.class, () -> BufferStack.of(1, -1)); - assertEquals("Negative byteAlignment: -1", exBA.getMessage()); - assertThrows(NullPointerException.class, () -> BufferStack.of(null)); - - BufferStack stack = newBufferStack(); - assertThrows(IllegalArgumentException.class, () -> stack.pushFrame(-1, 8)); - assertThrows(IllegalArgumentException.class, () -> stack.pushFrame(SMALL_ALLOC_SIZE, -1)); - - try (var arena = stack.pushFrame(SMALL_ALLOC_SIZE, 1)) { - assertThrows(IllegalArgumentException.class, () -> arena.allocate(-1)); - assertThrows(IllegalArgumentException.class, () -> arena.allocate(4, -1)); - } - } - - @Test - void invariantsVt() { - VThreadRunner.run(this::invariants); - } - - @Test - void testScopedAllocation() { - int stackSize = 128; - BufferStack stack = newBufferStack(); - try (Arena frame1 = stack.pushFrame(3 * JAVA_INT.byteSize(), JAVA_INT.byteAlignment())) { - // Segments have expected sizes and are accessible and allocated consecutively in the same scope. - MemorySegment segment11 = frame1.allocate(JAVA_INT); - assertEquals(frame1.scope(), segment11.scope()); - assertEquals(JAVA_INT.byteSize(), segment11.byteSize()); - segment11.set(JAVA_INT, 0, 1); - - MemorySegment segment12 = frame1.allocate(JAVA_INT); - assertEquals(segment11.address() + JAVA_INT.byteSize(), segment12.address()); - assertEquals(JAVA_INT.byteSize(), segment12.byteSize()); - assertEquals(frame1.scope(), segment12.scope()); - segment12.set(JAVA_INT, 0, 1); - - MemorySegment segment2; - try (Arena frame2 = stack.pushFrame(JAVA_LONG.byteSize(), JAVA_LONG.byteAlignment())) { - assertNotEquals(frame1.scope(), frame2.scope()); - // same here, but a new scope. - segment2 = frame2.allocate(JAVA_LONG); - assertEquals( segment12.address() + /*segment12 size + frame 1 spare + alignment constraint*/ 3 * JAVA_INT.byteSize(), segment2.address()); - assertEquals(JAVA_LONG.byteSize(), segment2.byteSize()); - assertEquals(frame2.scope(), segment2.scope()); - segment2.set(JAVA_LONG, 0, 1); - - // Frames must be closed in stack order. - assertThrows(IllegalStateException.class, frame1::close); - } - // Scope is closed here, inner segments throw. - assertThrows(IllegalStateException.class, () -> segment2.get(JAVA_INT, 0)); - // A new stack frame allocates at the same location (but different scope) as the previous did. - try (Arena frame3 = stack.pushFrame(2 * JAVA_INT.byteSize(), JAVA_INT.byteAlignment())) { - MemorySegment segment3 = frame3.allocate(JAVA_INT); - assertEquals(frame3.scope(), segment3.scope()); - assertEquals(segment12.address() + 2 * JAVA_INT.byteSize(), segment3.address()); - } - - // Fallback arena behaves like regular stack frame. - MemorySegment outOfStack; - try (Arena hugeFrame = stack.pushFrame(1024, 4)) { - outOfStack = hugeFrame.allocate(4); - assertEquals(hugeFrame.scope(), outOfStack.scope()); - assertTrue(outOfStack.asOverlappingSlice(segment11).isEmpty()); - } - assertThrows(IllegalStateException.class, () -> outOfStack.get(JAVA_INT, 0)); - - // Outer segments are still accessible. - segment11.get(JAVA_INT, 0); - segment12.get(JAVA_INT, 0); - } - } - - @Test - void testScopedAllocationVt() { - VThreadRunner.run(this::testScopedAllocation); - } - - static { - System.loadLibrary("TestBufferStack"); - } - - private static final MemoryLayout HVAPoint3D = structLayout(NativeTestHelper.C_DOUBLE, C_DOUBLE, C_DOUBLE); - private static final MemorySegment UPCALL_MH = upcallStub(TestBufferStack.class, "recurse", FunctionDescriptor.of(HVAPoint3D, C_INT)); - private static final MethodHandle DOWNCALL_MH = downcallHandle("recurse", FunctionDescriptor.of(HVAPoint3D, C_INT, ADDRESS)); - - public static MemorySegment recurse(int depth) { - try { - return (MemorySegment) DOWNCALL_MH.invokeExact((SegmentAllocator) Arena.ofAuto(), depth, UPCALL_MH); - } catch (Throwable e) { - throw new RuntimeException(e); - } - } - - @Test - void testDeepStack() { - // Each downcall and upcall require 48 bytes of stack. - // After five allocations we start falling back. - MemorySegment point = recurse(10); - assertEquals( 12.0, point.getAtIndex(C_DOUBLE, 0)); - assertEquals(11.0, point.getAtIndex(C_DOUBLE, 1)); - assertEquals( 10.0, point.getAtIndex(C_DOUBLE, 2)); - } - - @Test - void testDeepStackVt() { - VThreadRunner.run(this::testDeepStack); - } - - @Test - void equals() { - var first = newBufferStack(); - var second = newBufferStack(); - assertNotEquals(first, second); - assertEquals(first, first); - } - - @Test - void allocationSameAsPoolSize() { - MemoryLayout twoInts = MemoryLayout.sequenceLayout(2, JAVA_INT); - var pool = newBufferStack(); - long firstAddress; - try (var arena = pool.pushFrame(JAVA_INT)) { - var segment = arena.allocate(JAVA_INT); - firstAddress = segment.address(); - } - for (int i = 0; i < 10; i++) { - try (var arena = pool.pushFrame(twoInts)) { - var segment = arena.allocate(JAVA_INT); - assertEquals(firstAddress, segment.address()); - var segmentTwo = arena.allocate(JAVA_INT); - assertEquals(firstAddress + JAVA_INT.byteSize(), segmentTwo.address()); - // Questionable exception type - assertThrows(IndexOutOfBoundsException.class, () -> arena.allocate(JAVA_INT)); - } - } - } - @Test - void allocationSameAsPoolSizeVt() { - VThreadRunner.run(this::allocationSameAsPoolSize); - } - - @Test - void allocateConfinement() { - var pool = newBufferStack(); - Consumer allocateAction = arena -> - assertThrows(WrongThreadException.class, () -> { - CompletableFuture future = CompletableFuture.supplyAsync(() -> pool.pushFrame(SMALL_ALLOC_SIZE, 1)); - var otherThreadArena = future.get(); - otherThreadArena.allocate(SMALL_ALLOC_SIZE); - // Intentionally do not close the otherThreadArena here. - }); - doInTwoStackedArenas(pool, allocateAction, allocateAction); - } - - @Test - void allocateConfinementVt() { - VThreadRunner.run(this::allocateConfinement); - } - - @Test - void closeConfinement() { - var pool = newBufferStack(); - Consumer closeAction = arena -> { - // Do not use CompletableFuture here as it might accidentally run on the - // same carrier thread as a virtual thread. - AtomicReference otherThreadArena = new AtomicReference<>(); - var thread = Thread.ofPlatform().start(() -> { - otherThreadArena.set(pool.pushFrame(SMALL_ALLOC_SIZE, 1)); - }); - try { - thread.join(); - } catch (InterruptedException ie) { - fail(ie); - } - assertThrows(WrongThreadException.class, otherThreadArena.get()::close); - }; - doInTwoStackedArenas(pool, closeAction, closeAction); - } - - @Test - void closeConfinementVt() { - VThreadRunner.run(this::closeConfinement); - } - - @Test - void toStringTest() { - BufferStack stack = newBufferStack(); - assertEquals("BufferStack[byteSize=" + POOL_SIZE + ", byteAlignment=1]", stack.toString()); - } - - @Test - void allocBounds() { - BufferStack stack = newBufferStack(); - try (var arena = stack.pushFrame(SMALL_ALLOC_SIZE, 1)) { - assertThrows(IllegalArgumentException.class, () -> arena.allocate(-1)); - assertDoesNotThrow(() -> arena.allocate(SMALL_ALLOC_SIZE)); - assertThrows(IndexOutOfBoundsException.class, () -> arena.allocate(SMALL_ALLOC_SIZE + 1)); - } - } - - @Test - void accessBounds() { - BufferStack stack = newBufferStack(); - try (var arena = stack.pushFrame(SMALL_ALLOC_SIZE, 1)) { - var segment = arena.allocate(SMALL_ALLOC_SIZE); - assertThrows(IndexOutOfBoundsException.class, () -> segment.get(JAVA_BYTE, SMALL_ALLOC_SIZE)); - } - } - - @Test - void noInit() { - BufferStack stack = newBufferStack(); - try (var arena = stack.pushFrame(SMALL_ALLOC_SIZE, 1)) { - assertDoesNotThrow(() -> arena.allocateFrom(JAVA_INT, 1)); - } - } - - static void doInTwoStackedArenas(BufferStack pool, - Consumer firstAction, - Consumer secondAction) { - try (var firstArena = pool.pushFrame(SMALL_ALLOC_SIZE, 1)) { - firstAction.accept(firstArena); - try (var secondArena = pool.pushFrame(SMALL_ALLOC_SIZE, 1)) { - secondAction.accept(secondArena); - } - } - } - - private static BufferStack newBufferStack() { - return BufferStack.of(POOL_SIZE, 1); - } - - -} diff --git a/test/jdk/java/foreign/TestBufferStackStress.java b/test/jdk/java/foreign/TestBufferStackStress.java deleted file mode 100644 index a0b7348331ce..000000000000 --- a/test/jdk/java/foreign/TestBufferStackStress.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2025, 2026, 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 java.base/jdk.internal.foreign - * @library /test/lib - * @run junit TestBufferStackStress - */ - -import jdk.internal.foreign.BufferStack; -import jdk.test.lib.Platform; -import org.junit.jupiter.api.Test; - -import java.lang.foreign.Arena; -import java.lang.foreign.MemorySegment; -import java.time.Duration; -import java.util.Arrays; -import java.util.stream.IntStream; - -import static java.lang.foreign.ValueLayout.*; -import static java.time.temporal.ChronoUnit.SECONDS; -import static org.junit.jupiter.api.Assertions.*; -import static org.junit.jupiter.api.Assumptions.*; - -final class TestBufferStackStress { - - @Test - void stress() throws InterruptedException { - if (Platform.isOSX()) { - // 8350455 was only fixed in macOS versions 26 or higher - assumeFalse(Platform.getOsVersionMajor() < 26, "Unsupported OS version: " + Platform.getOsVersionMajor()); - } - - BufferStack stack = BufferStack.of(256, 1); - Thread[] vThreads = IntStream.range(0, 512).mapToObj(_ -> - Thread.ofVirtual().start(() -> { - long threadId = Thread.currentThread().threadId(); - while (!Thread.interrupted()) { - for (int i = 0; i < 500_000; i++) { - try (Arena arena = stack.pushFrame(JAVA_LONG.byteSize(), JAVA_LONG.byteAlignment())) { - // Try to assert no two vThreads get allocated the same stack space. - MemorySegment segment = arena.allocate(JAVA_LONG); - JAVA_LONG.varHandle().setVolatile(segment, 0L, threadId); - assertEquals(threadId, (long) JAVA_LONG.varHandle().getVolatile(segment, 0L)); - } - } - Thread.yield(); // make sure the driver thread gets a chance. - } - })).toArray(Thread[]::new); - Thread.sleep(Duration.of(10, SECONDS)); - Arrays.stream(vThreads).forEach( - thread -> { - assertTrue(thread.isAlive()); - thread.interrupt(); - }); - } - -} diff --git a/test/jdk/java/foreign/TestBufferStackStress2.java b/test/jdk/java/foreign/TestBufferStackStress2.java deleted file mode 100644 index cf02d5ae6083..000000000000 --- a/test/jdk/java/foreign/TestBufferStackStress2.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2025, 2026, 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 - * - * @comment If the VM does not have continuations, then VTs will be scheduled on OS threads. - * @requires vm.continuations - * - * @bug 8356114 8356658 - * @modules java.base/jdk.internal.foreign - * @run junit/timeout=480 TestBufferStackStress2 - */ - -import jdk.internal.foreign.BufferStack; -import org.junit.jupiter.api.Assumptions; -import org.junit.jupiter.api.Test; - -import java.io.FileDescriptor; -import java.lang.foreign.Arena; -import java.lang.foreign.MemorySegment; -import java.lang.foreign.ValueLayout; -import java.time.Duration; -import java.time.temporal.ChronoUnit; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Executors; -import java.util.concurrent.ForkJoinWorkerThread; -import java.util.concurrent.atomic.AtomicBoolean; - -import static org.junit.jupiter.api.Assertions.*; - -final class TestBufferStackStress2 { - - private static final long POOL_SIZE = 64; - private static final long SMALL_ALLOC_SIZE = 8; - - /** - * The objective with this test is to test the case when a virtual thread VT0 is - * mounted on a carrier thread CT0; VT0 is then suspended; The pool of carrier threads - * are then contracted; VT0 is then remounted on another carrier thread C1. VT0 runs - * for a while when there is a lot of GC activity. - * In other words, we are trying to establish that there is no use-after-free and that - * the original arena, from which reusable segments are initially allocated from, is - * not closed underneath. - *

    - * Unfortunately, this test takes about 30 seconds as that is the time it takes for - * the pool of carrier threads to be contracted. - */ - @Test - void movingVirtualThreadWithGc() throws InterruptedException { - - // If the VM is configured such that the main thread is virtual, - // this stress test will not work as the main thread is always alive causing - // us to wait forever for contraction. - // Hence, we will skip this test if the main thread is virtual. - Assumptions.assumeFalse(Thread.currentThread().isVirtual(), - "Skipped because the main thread is a virtual thread"); - - final long begin = System.nanoTime(); - var pool = BufferStack.of(POOL_SIZE, 1); - - System.setProperty("jdk.virtualThreadScheduler.parallelism", "1"); - - var done = new AtomicBoolean(); - var completed = new AtomicBoolean(); - var quiescentLatch = new CountDownLatch(1); - - var executor = Executors.newVirtualThreadPerTaskExecutor(); - - executor.submit(() -> { - while (!done.get()) { - FileDescriptor.out.sync(); - } - return null; - }); - - executor.submit(() -> { - System.out.println(duration(begin) + "ALLOCATING = " + Thread.currentThread()); - try (Arena arena = pool.pushFrame(SMALL_ALLOC_SIZE, 1)) { - MemorySegment segment = arena.allocate(SMALL_ALLOC_SIZE); - done.set(true); - // wait for ForkJoinPool to contract - try { - quiescentLatch.await(); - } catch (Throwable ex) { - throw new AssertionError(ex); - } - System.out.println(duration(begin) + "ACCESSING SEGMENT"); - - for (int i = 0; i < 100_000; i++) { - if (i % 100 == 0) { - System.gc(); - } - segment.get(ValueLayout.JAVA_BYTE, i % SMALL_ALLOC_SIZE); - } - System.out.println(duration(begin) + "DONE ACCESSING SEGMENT"); - } - System.out.println(duration(begin) + "VT DONE"); - completed.set(true); - }); - - long count; - do { - Thread.sleep(1000); - count = Thread.getAllStackTraces().keySet().stream() - .filter(t -> t instanceof ForkJoinWorkerThread) - .count(); - } while (count > 0); - - System.out.println(duration(begin) + "FJP HAS CONTRACTED"); - quiescentLatch.countDown(); // notify the thread that accesses the MemorySegment - - System.out.println(duration(begin) + "CLOSING EXECUTOR"); - executor.close(); - System.out.println(duration(begin) + "EXECUTOR CLOSED"); - - assertTrue(completed.get(), "The VT did not complete properly"); - } - - private static String duration(Long begin) { - var duration = Duration.of(System.nanoTime() - begin, ChronoUnit.NANOS); - long seconds = duration.toSeconds(); - int nanos = duration.toNanosPart(); - return (Thread.currentThread().isVirtual() ? "VT: " : "PT: ") + - String.format("%3d:%09d ", seconds, nanos); - } - -} diff --git a/test/jdk/java/foreign/TestCaptureStateUtil.java b/test/jdk/java/foreign/TestCaptureStateUtil.java deleted file mode 100644 index c4f0e038f09b..000000000000 --- a/test/jdk/java/foreign/TestCaptureStateUtil.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * 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 - * @summary Test CaptureStateUtil - * @modules java.base/jdk.internal.foreign - * @run junit TestCaptureStateUtil - */ - -import jdk.internal.foreign.CaptureStateUtil; -import org.junit.jupiter.api.Test; - -import java.lang.foreign.Linker; -import java.lang.foreign.MemoryLayout; -import java.lang.foreign.MemorySegment; -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; -import java.lang.invoke.VarHandle; - -import static org.junit.jupiter.api.Assertions.*; - -final class TestCaptureStateUtil { - - private static final String ERRNO_NAME = "errno"; - - private static final VarHandle ERRNO_HANDLE = Linker.Option.captureStateLayout() - .varHandle(MemoryLayout.PathElement.groupElement(ERRNO_NAME)); - - private static final MethodHandle INT_DUMMY_HANDLE; - private static final MethodHandle LONG_DUMMY_HANDLE; - - static { - try { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - INT_DUMMY_HANDLE = lookup - .findStatic(TestCaptureStateUtil.class, "dummy", - MethodType.methodType(int.class, MemorySegment.class, int.class, int.class)); - LONG_DUMMY_HANDLE = lookup - .findStatic(TestCaptureStateUtil.class, "dummy", - MethodType.methodType(long.class, MemorySegment.class, long.class, int.class)); - } catch (ReflectiveOperationException e) { - throw new InternalError(e); - } - } - - private static final MethodHandle ADAPTED_INT = CaptureStateUtil - .adaptSystemCall(INT_DUMMY_HANDLE, ERRNO_NAME); - private static final MethodHandle ADAPTED_LONG = CaptureStateUtil - .adaptSystemCall(LONG_DUMMY_HANDLE, ERRNO_NAME); - - @Test - void successfulInt() throws Throwable { - int r = (int) ADAPTED_INT.invokeExact(1, 0); - assertEquals(1, r); - } - - private static final int EACCES = 13; /* Permission denied */ - - @Test - void errorInt() throws Throwable { - int r = (int) ADAPTED_INT.invokeExact(-1, EACCES); - assertEquals(-EACCES, r); - } - - @Test - void successfulLong() throws Throwable { - long r = (long) ADAPTED_LONG.invokeExact(1L, 0); - assertEquals(1, r); - } - - @Test - void errorLong() throws Throwable { - long r = (long) ADAPTED_LONG.invokeExact(-1L, EACCES); - assertEquals(-EACCES, r); - } - - @Test - void successfulIntPerHandle() throws Throwable { - MethodHandle handle = CaptureStateUtil - .adaptSystemCall(INT_DUMMY_HANDLE, ERRNO_NAME); - int r = (int) handle.invokeExact(1, 0); - assertEquals(1, r); - } - - @Test - void invariants() throws Throwable { - MethodHandle noSegment = MethodHandles.lookup() - .findStatic(TestCaptureStateUtil.class, "wrongType", - MethodType.methodType(long.class, long.class, int.class)); - - var noSegEx = assertThrows(IllegalArgumentException.class, () -> CaptureStateUtil.adaptSystemCall(noSegment, ERRNO_NAME)); - assertTrue(noSegEx.getMessage().contains("does not have a MemorySegment as the first parameter")); - - MethodHandle noArgMH = MethodHandles.empty(MethodType.methodType(int.class)); - var emptyEx = assertThrows(IllegalArgumentException.class, () -> CaptureStateUtil.adaptSystemCall(noArgMH, ERRNO_NAME)); - assertTrue(emptyEx.getMessage().contains("does not have a MemorySegment as the first parameter")); - - MethodHandle wrongReturnType = MethodHandles.lookup() - .findStatic(TestCaptureStateUtil.class, "wrongType", - MethodType.methodType(short.class, MemorySegment.class, long.class, int.class)); - - var wrongRetEx = assertThrows(IllegalArgumentException.class, () -> CaptureStateUtil.adaptSystemCall(wrongReturnType, ERRNO_NAME)); - assertTrue(wrongRetEx.getMessage().contains("does not return an int or a long")); - - var wrongCaptureName = assertThrows(IllegalArgumentException.class, () -> CaptureStateUtil.adaptSystemCall(LONG_DUMMY_HANDLE, "foo")); - assertEquals("Input not allowed: SegmentExtractorKey[returnType=long, stateName=foo]", wrongCaptureName.getMessage()); - - assertThrows(NullPointerException.class, () -> CaptureStateUtil.adaptSystemCall(null, ERRNO_NAME)); - assertThrows(IllegalArgumentException.class, () -> CaptureStateUtil.adaptSystemCall(noSegment, null)); - } - - // Dummy method that is just returning the provided parameters - private static int dummy(MemorySegment segment, int result, int errno) { - ERRNO_HANDLE.set(segment, 0, errno); - return result; - } - - // Dummy method that is just returning the provided parameters - private static long dummy(MemorySegment segment, long result, int errno) { - ERRNO_HANDLE.set(segment, 0, errno); - return result; - } - - private static long wrongType(long result, int errno) { - return 0; - } - - private static short wrongType(MemorySegment segment, long result, int errno) { - return 0; - } - -} diff --git a/test/jdk/java/foreign/sharedclosejfr/TestSharedCloseJFR.java b/test/jdk/java/foreign/sharedclosejfr/TestSharedCloseJFR.java index 913be05ac502..01a52102246d 100644 --- a/test/jdk/java/foreign/sharedclosejfr/TestSharedCloseJFR.java +++ b/test/jdk/java/foreign/sharedclosejfr/TestSharedCloseJFR.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, 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 8370344 + * @bug 8370344 8387577 * @requires os.family != "windows" * @requires vm.flavor != "zero" * @requires vm.hasJFR diff --git a/test/jdk/java/lang/invoke/FoldTest.java b/test/jdk/java/lang/invoke/FoldTest.java index 92ba246ebc8a..a1c5d162ccaa 100644 --- a/test/jdk/java/lang/invoke/FoldTest.java +++ b/test/jdk/java/lang/invoke/FoldTest.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 8139885 + * @bug 8139885 8367022 * @run junit/othervm -ea -esa test.java.lang.invoke.FoldTest */ @@ -37,8 +37,11 @@ import static java.lang.invoke.MethodType.methodType; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; /** * Tests for the new fold method handle combinator added in JEP 274. @@ -92,6 +95,35 @@ public void testFoldArgumentsExample() throws Throwable { assertEquals("jum", swr.toString()); } + static Object[][] invalidFoldPositions() { + return new Object[][] { + {-1}, + {Integer.MIN_VALUE}, + {Fold.MH_multer.type().parameterCount()}, + {Integer.MAX_VALUE} + }; + } + + @ParameterizedTest + @MethodSource("invalidFoldPositions") + public void testInvalidFoldPositions(int pos) { + MethodHandle voidCombiner = MethodHandles.empty(methodType(void.class, int.class)); + assertThrows(IllegalArgumentException.class, + () -> MethodHandles.foldArguments(Fold.MH_multer, pos, Fold.MH_adder1)); + assertThrows(IllegalArgumentException.class, + () -> MethodHandles.foldArguments(Fold.MH_multer, pos, voidCombiner)); + } + + @Test + public void testVoidFoldAtEnd() throws Throwable { + MethodHandle voidCombiner = MethodHandles.empty(methodType(void.class)); + int position = Fold.MH_multer.type().parameterCount(); + MethodHandle fold = MethodHandles.foldArguments(Fold.MH_multer, position, voidCombiner); + + assertEquals(Fold.MT_multer, fold.type()); + assertEquals(120, (int) fold.invoke(2, 3, 4, 5)); + } + static class Fold { static int adder(int a, int b, int c) { diff --git a/test/jdk/java/math/BigDecimal/ToBigIntegerTests.java b/test/jdk/java/math/BigDecimal/ToBigIntegerTests.java new file mode 100644 index 000000000000..18faa55ac545 --- /dev/null +++ b/test/jdk/java/math/BigDecimal/ToBigIntegerTests.java @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2026, 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 8393682 + * @summary Tests of BigDecimal.{toBigInteger, toBigIntegerExact} + */ + +import java.math.*; + +public class ToBigIntegerTests { + public static void main(String... args) { + int failures = 0; + + failures += zeroTestCases(); + failures += toBigIntegerTests(); + failures += toBigIntegerExactTests(); + + if (failures > 0) { + throw new RuntimeException("Incurred " + failures + + " failures while testing toBigInteger/toBigIntegerExact."); + } + } + + private static record TbiTestCase(BigDecimal input, BigInteger expected) { + static TbiTestCase of(BigDecimal input, BigInteger expected) { + return new TbiTestCase(input, expected); + } + + static TbiTestCase of(String input, BigInteger expected) { + return new TbiTestCase(new BigDecimal(input), expected); + } + } + + private static TbiTestCase zeroTestCases[] = { + TbiTestCase.of(new BigDecimal(BigInteger.ZERO, + Integer.MIN_VALUE), BigInteger.ZERO), + TbiTestCase.of(new BigDecimal(BigInteger.ZERO, -1), BigInteger.ZERO), + TbiTestCase.of(BigDecimal.ZERO, BigInteger.ZERO), + TbiTestCase.of(new BigDecimal(BigInteger.ZERO, +1), BigInteger.ZERO), + TbiTestCase.of(new BigDecimal(BigInteger.ZERO, + Integer.MAX_VALUE), BigInteger.ZERO), + }; + + private static int zeroTestCases() { + int failures = 0; + + for(var zeroTestCase : zeroTestCases) { + BigDecimal input = zeroTestCase.input; + BigInteger expected = zeroTestCase.expected; + + if (!input.toBigInteger().equals(expected)) { + failures++; + System.out.println(input + " did not have expected toBigInteger result of " + expected); + } + + if (!input.toBigIntegerExact().equals(expected)) { + failures++; + System.out.println(input + " did not have toBigIntegerExact result of " + expected); + } + } + + return failures; + } + + private static TbiTestCase tbiTestCases[] = { + // nonzero constant values in the API + TbiTestCase.of(BigDecimal.ONE, BigInteger.ONE), + TbiTestCase.of(BigDecimal.TWO, BigInteger.TWO), + TbiTestCase.of(BigDecimal.TEN, BigInteger.TEN), + + // Negative scale values with (precision == 1) + TbiTestCase.of( "1e1", BigInteger.TEN), + TbiTestCase.of( "1e2", BigInteger.valueOf( 100)), + TbiTestCase.of( "1e3", BigInteger.valueOf( 1_000)), + TbiTestCase.of( "1e6", BigInteger.valueOf(1_000_000)), + + // Scale == 0 values, varying precision + TbiTestCase.of(BigDecimal.valueOf( 12, 0), BigInteger.valueOf( 12)), + TbiTestCase.of(BigDecimal.valueOf( 123, 0), BigInteger.valueOf( 123)), + TbiTestCase.of(BigDecimal.valueOf(1234, 0), BigInteger.valueOf(1234)), + + // Positive scale, varying precision + TbiTestCase.of(BigDecimal.valueOf( 12, 1), BigInteger.valueOf( 1)), + TbiTestCase.of(BigDecimal.valueOf( 123, 1), BigInteger.valueOf( 12)), + TbiTestCase.of(BigDecimal.valueOf(1234, 1), BigInteger.valueOf(123)), + + TbiTestCase.of(BigDecimal.valueOf( 12, 2), BigInteger.valueOf( 0)), + TbiTestCase.of(BigDecimal.valueOf( 123, 2), BigInteger.valueOf( 1)), + TbiTestCase.of(BigDecimal.valueOf(1234, 2), BigInteger.valueOf(12)), + + TbiTestCase.of(BigDecimal.valueOf( 12, 3), BigInteger.valueOf(0)), + TbiTestCase.of(BigDecimal.valueOf( 123, 3), BigInteger.valueOf(0)), + TbiTestCase.of(BigDecimal.valueOf(1234, 3), BigInteger.valueOf(1)), + + // More fractional values + TbiTestCase.of("-0.5", BigInteger.ZERO), + TbiTestCase.of( "0.5", BigInteger.ZERO), + + TbiTestCase.of("-0.5001", BigInteger.ZERO), + TbiTestCase.of( "0.5001", BigInteger.ZERO), + + TbiTestCase.of("-0.9999", BigInteger.ZERO), + TbiTestCase.of( "0.9999", BigInteger.ZERO), + + TbiTestCase.of( "0.0001", BigInteger.ZERO), + TbiTestCase.of("-0.0001", BigInteger.ZERO), + + TbiTestCase.of( "1e-15", BigInteger.ZERO), + TbiTestCase.of("-1e-15", BigInteger.ZERO), + + // Test rounding to 1 + TbiTestCase.of("-1.5", BigInteger.ONE.negate()), + TbiTestCase.of( "1.5", BigInteger.ONE), + + TbiTestCase.of("-1.5001", BigInteger.ONE.negate()), + TbiTestCase.of( "1.5001", BigInteger.ONE), + + TbiTestCase.of("-1.9999", BigInteger.ONE.negate()), + TbiTestCase.of( "1.9999", BigInteger.ONE), + + TbiTestCase.of( "1.0001", BigInteger.ONE), + TbiTestCase.of("-1.0001", BigInteger.ONE.negate()), + }; + + private static int toBigIntegerTests() { + int failures = 0; + + for(var tbiTestCase : tbiTestCases) { + BigDecimal input = tbiTestCase.input; + BigInteger expected = tbiTestCase.expected; + + if (!input.toBigInteger().equals(expected)) { + failures++; + System.out.println(input + " did not have expected toBigInteger of result of " + expected); + } + } + + return failures; + } + + private static TbiTestCase tbiExactTestCases[] = { + // nonzero constant value in the API + TbiTestCase.of(BigDecimal.ONE, BigInteger.ONE), + TbiTestCase.of(BigDecimal.TWO, BigInteger.TWO), + TbiTestCase.of(BigDecimal.TEN, BigInteger.TEN), + + // Negative scale values with (precision == 1) + TbiTestCase.of( "1e1", BigInteger.TEN), + TbiTestCase.of( "1e2", BigInteger.valueOf( 100)), + TbiTestCase.of( "1e3", BigInteger.valueOf( 1_000)), + TbiTestCase.of( "1e6", BigInteger.valueOf(1_000_000)), + + // Scale == 0 values, varying precision + TbiTestCase.of(BigDecimal.valueOf( 12, 0), BigInteger.valueOf( 12)), + TbiTestCase.of(BigDecimal.valueOf( 123, 0), BigInteger.valueOf( 123)), + TbiTestCase.of(BigDecimal.valueOf(1234, 0), BigInteger.valueOf(1234)), + + // Positive scale, varying precision + TbiTestCase.of(BigDecimal.valueOf( 12, 1), null), + TbiTestCase.of(BigDecimal.valueOf( 123, 1), null), + TbiTestCase.of(BigDecimal.valueOf(1234, 1), null), + + TbiTestCase.of(BigDecimal.valueOf( 12, 2), null), + TbiTestCase.of(BigDecimal.valueOf( 123, 2), null), + TbiTestCase.of(BigDecimal.valueOf(1234, 2), null), + + TbiTestCase.of(BigDecimal.valueOf( 12, 3), null), + TbiTestCase.of(BigDecimal.valueOf( 123, 3), null), + TbiTestCase.of(BigDecimal.valueOf(1234, 3), null), + + // More fractional values + TbiTestCase.of("-0.9999", null), + TbiTestCase.of( "0.9999", null), + + TbiTestCase.of( "0.0001", null), + TbiTestCase.of("-0.0001", null), + + + TbiTestCase.of( "1e-15", null), + TbiTestCase.of("-1e-15", null), + }; + + private static int toBigIntegerExactTests() { + int failures = 0; + + for(var tbiTestCase : tbiExactTestCases) { + BigDecimal input = tbiTestCase.input; + BigInteger expected = tbiTestCase.expected; + BigInteger result = null; + + if (expected == null) { // ArithmeticException expected + try { + result = input.toBigIntegerExact(); + failures++; + System.out.println("Got unexpected non-exceptionsl result of toBigIntegerExact on " + input); + } catch(ArithmeticException ae) { + ; // Expected + } + } else { + try { + result = input.toBigIntegerExact(); + if (!result.equals(expected)) { + failures++; + System.out.println(input + " did not have expected toBigIntegerExact of " + expected); + } + } catch(ArithmeticException ae) { + failures++; + System.out.println("Unexpected exception computing toBigIntegerExact of " + input); + } + } + } + return failures; + } +} diff --git a/test/jdk/java/net/Socket/SetSoLinger.java b/test/jdk/java/net/Socket/SetSoLinger.java index 77e3fe761959..190182d1c6ab 100644 --- a/test/jdk/java/net/Socket/SetSoLinger.java +++ b/test/jdk/java/net/Socket/SetSoLinger.java @@ -23,7 +23,7 @@ /* * @test - * @bug 4151834 8392732 + * @bug 4151834 8392732 8393721 * @summary Test Socket.setSoLinger * @library /test/lib * @build jdk.test.lib.Platform jdk.test.lib.net.IPSupport @@ -41,9 +41,9 @@ import jdk.test.lib.net.IPSupport; public class SetSoLinger { - // on macos the linger value is limited to 32767 and on + // on bsd and macos the linger value is limited to 32767 and on // rest of the platforms it is limited to 65535 - private static final int EXPECTED_MAX_LINGER = Platform.isOSX() ? 32767 : 65535; + private static final int EXPECTED_MAX_LINGER = Platform.isOSX() || Platform.isBSD() ? 32767 : 65535; // some arbitrary large linger value which is greater the max limit private static final int LARGE_LINGER = EXPECTED_MAX_LINGER + 42; diff --git a/test/jdk/java/net/httpclient/ImmutableSSLSessionTest.java b/test/jdk/java/net/httpclient/ImmutableSSLSessionTest.java index a7c9deddac72..7545ecd1f626 100644 --- a/test/jdk/java/net/httpclient/ImmutableSSLSessionTest.java +++ b/test/jdk/java/net/httpclient/ImmutableSSLSessionTest.java @@ -60,7 +60,6 @@ import static java.net.http.HttpClient.Version.HTTP_2; import static java.net.http.HttpClient.Version.HTTP_3; import static java.net.http.HttpOption.H3_DISCOVERY; -import static java.net.http.HttpOption.Http3DiscoveryMode.ALT_SVC; import static java.net.http.HttpOption.Http3DiscoveryMode.HTTP_3_URI_ONLY; import static java.nio.charset.StandardCharsets.US_ASCII; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -242,6 +241,7 @@ private void checkDummySession(SSLSession session) throws Exception { assertEquals(List.of("foo", "bar"), Arrays.asList(ext.getLocalSupportedSignatureAlgorithms())); assertEquals(List.of(new SNIHostName("localhost")), ((ExtendedSSLSession) session).getRequestedServerNames()); + assertEquals("MyNamedGroup", ((ExtendedSSLSession) session).getNamedGroup()); List status = ext.getStatusResponses(); assertEquals(1, status.size()); assertEquals("42", new String(status.get(0), US_ASCII)); @@ -363,6 +363,11 @@ public String[] getPeerSupportedSignatureAlgorithms() { return new String[] {"bar", "foo"}; } + @Override + public String getNamedGroup() { + return "MyNamedGroup"; + } + @Override public List getRequestedServerNames() { return List.of(new SNIHostName("localhost")); diff --git a/test/jdk/java/net/vthread/BlockingSocketOps.java b/test/jdk/java/net/vthread/BlockingSocketOps.java index d3db734f36a5..629406967aff 100644 --- a/test/jdk/java/net/vthread/BlockingSocketOps.java +++ b/test/jdk/java/net/vthread/BlockingSocketOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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,26 +23,33 @@ /* * @test id=default - * @bug 8284161 8372958 + * @bug 8284161 8372958 8394217 * @summary Test virtual threads doing blocking I/O on java.net Sockets * @library /test/lib - * @run junit BlockingSocketOps + * @run junit ${test.main.class} */ /* * @test id=poller-modes * @requires (os.family == "linux") | (os.family == "mac") * @library /test/lib - * @run junit/othervm -Djdk.pollerMode=1 BlockingSocketOps - * @run junit/othervm -Djdk.pollerMode=2 BlockingSocketOps - * @run junit/othervm -Djdk.pollerMode=3 BlockingSocketOps + * @run junit/othervm -Djdk.pollerMode=1 ${test.main.class} + * @run junit/othervm -Djdk.pollerMode=2 ${test.main.class} + * @run junit/othervm -Djdk.pollerMode=3 ${test.main.class} + */ + +/* + * @test id=no-write-poller-thread + * @requires (os.family == "linux") | (os.family == "mac") + * @library /test/lib + * @run junit/othervm -Djdk.pollerMode=1 -Djdk.writePollers=0 ${test.main.class} */ /* * @test id=no-vmcontinuations * @requires vm.continuations * @library /test/lib - * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations BlockingSocketOps + * @run junit/othervm -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations ${test.main.class} */ import java.io.Closeable; diff --git a/test/jdk/java/nio/channels/Channels/Available.java b/test/jdk/java/nio/channels/Channels/Available.java index 9e37598bbb67..4c02aa062aa2 100644 --- a/test/jdk/java/nio/channels/Channels/Available.java +++ b/test/jdk/java/nio/channels/Channels/Available.java @@ -44,55 +44,67 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.Arrays; +import java.util.stream.IntStream; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import static org.junit.jupiter.api.Assertions.*; class Available { + /** + * Supplies (file) sizes and positions to test. + */ + static Stream testCases() { + return IntStream.of(0, 1, 100) // sizes + .boxed() + .flatMap(size -> { + long[] positions = { + 0, + 1, + 2, + size - 1, + size, + size + 1, + Integer.MAX_VALUE - size - 1, + Integer.MAX_VALUE - size, + Integer.MAX_VALUE - size + 1, + Integer.MAX_VALUE - 1, + Integer.MAX_VALUE, + Integer.MAX_VALUE + 1L + }; + return Arrays.stream(positions) + .filter(pos -> pos >= 0) + .distinct() + .mapToObj(pos -> Arguments.of(size, pos)); + }); + } + /** * Test InputStream.available when input stream reads from a SeekableByteChannel. */ - private static void testSeekableByteChannel(SeekableByteChannel ch) throws Exception { + private static void testAvailable(SeekableByteChannel ch) throws Exception { InputStream in = Channels.newInputStream(ch); - long size = ch.size(); - long[] positions = new long[] { - 0L, - size - 1L, - size, - size + 1L, - Integer.MAX_VALUE - size - 1L, - Integer.MAX_VALUE - size, - Integer.MAX_VALUE - size + 1L, - Integer.MAX_VALUE - 1L, - Integer.MAX_VALUE, - Integer.MAX_VALUE + 1L - }; - for (long pos : positions) { - if (pos >= 0) { - int expectedAvailable = Math.clamp(size - pos, 0, Integer.MAX_VALUE); - System.err.format( - " size = %d, position = %d, expected available = %d%n", - size, pos, expectedAvailable); - ch.position(pos); - assertEquals(expectedAvailable, in.available()); - } - } + int expectedAvailable = Math.clamp(ch.size() - ch.position(), 0, Integer.MAX_VALUE); + assertEquals(expectedAvailable, in.available()); } /** * Test InputStream.available when input stream reads from a FileChannel. */ @ParameterizedTest - @ValueSource(ints = { 0, 100 }) - void testFileChannel(int size) throws Exception { + @MethodSource("testCases") + void testFileChannel(int size, long pos) throws Exception { Path file = Files.createTempFile(Path.of("."), "blah", "dat"); try { Files.write(file, new byte[size]); try (FileChannel fc = FileChannel.open(file)) { - testSeekableByteChannel(fc); + fc.position(pos); + testAvailable(fc); } } finally { Files.delete(file); @@ -103,8 +115,8 @@ void testFileChannel(int size) throws Exception { * Test InputStream.available when input stream reads from a SeekableByteChannel. */ @ParameterizedTest - @ValueSource(ints = { 0, 100 }) - void testSeekableByteChannel(int size) throws Exception { + @MethodSource("testCases") + void testSeekableByteChannel(int size, long pos) throws Exception { var ch = new SeekableByteChannel() { long position; @Override @@ -143,7 +155,9 @@ public void close() throws IOException { throw new IOException(); } }; - testSeekableByteChannel(ch); + + ch.position(pos); + testAvailable(ch); } /** diff --git a/test/jdk/java/nio/channels/Channels/Skip.java b/test/jdk/java/nio/channels/Channels/Skip.java new file mode 100644 index 000000000000..86586a3c7401 --- /dev/null +++ b/test/jdk/java/nio/channels/Channels/Skip.java @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2026, 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 8394316 + * @summary Test Channels.newInputStream skip method + * @run junit ${test.main.class} + */ + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.ByteBuffer; +import java.nio.channels.Channels; +import java.nio.channels.FileChannel; +import java.nio.channels.NonWritableChannelException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SeekableByteChannel; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.*; + +class Skip { + + /** + * Supplies (file) sizes, positions and skip values to test. + */ + static Stream testCases() { + return IntStream.of(0, 1, 100) // sizes + .boxed() + .flatMap(size -> { + long[] positions = { + 0, + 1, + 2, + size - 1L, + size, + size + 1L, + Integer.MAX_VALUE - 1, + Integer.MAX_VALUE + }; + long[] skips = { + Long.MIN_VALUE, + Long.MIN_VALUE + 1, + -size - 1, + -size, + -size + 1, + -2, + -1, + 0, + 1, + 2, + size - 1, + size, + size + 1, + Long.MAX_VALUE - 1, + Long.MAX_VALUE + }; + return Arrays.stream(positions) + .filter(pos -> pos >= 0) + .distinct() + .boxed() + .flatMap(position -> Arrays.stream(skips) + .distinct() + .mapToObj(skip -> Arguments.of(size, position, skip))); + }); + } + + + /** + * Test InputStream.skip when input stream reads from a SeekableByteChannel. + */ + private static void testSkip(SeekableByteChannel ch, long skip) throws Exception { + InputStream in = Channels.newInputStream(ch); + long pos = ch.position(); + long expectSkip = (skip >= 0) + ? Long.min(skip, Long.max(ch.size() - pos, 0L)) + : Long.max(-pos, skip); + assertEquals(expectSkip, in.skip(skip), "skip"); + assertEquals(pos + expectSkip, ch.position(), "position"); + } + + /** + * Test InputStream.skip when input stream reads from a FileChannel. + */ + @ParameterizedTest + @MethodSource("testCases") + void testFileChannel(int size, long pos, long skip) throws Exception { + Path file = Files.createTempFile(Path.of("."), "blah", "dat"); + try { + Files.write(file, new byte[size]); + try (FileChannel fc = FileChannel.open(file)) { + fc.position(pos); + testSkip(fc, skip); + } + } finally { + Files.delete(file); + } + } + + /** + * Test InputStream.skip when input stream reads from a SeekableByteChannel. + */ + @ParameterizedTest + @MethodSource("testCases") + void testSeekableByteChannel(int size, long pos, long skip) throws Exception { + byte[] bytes = "X".repeat(size).getBytes("UTF-8"); + + var ch = new SeekableByteChannel() { + int offset; + @Override + public int read(ByteBuffer dst) { + if (!dst.hasRemaining()) + return 0; + if (offset >= size) + return -1; + int n = (int) Long.min(dst.remaining(), size - offset); + dst.put(bytes, offset, n); + offset += n; + return n; + } + @Override + public int write(ByteBuffer src) { + throw new NonWritableChannelException(); + } + @Override + public long position() { + return offset; + } + @Override + public SeekableByteChannel position(long newPosition) { + if (newPosition < 0 || newPosition > Integer.MAX_VALUE) + throw new IllegalArgumentException(); + offset = (int) newPosition; + return this; + } + @Override + public long size() { + return size; + } + @Override + public SeekableByteChannel truncate(long size) throws IOException { + throw new IOException(); + } + @Override + public boolean isOpen() { + return true; + } + @Override + public void close() throws IOException { + throw new IOException(); + } + }; + + ch.position(pos); + testSkip(ch, skip); + } + + /** + * Test InputStream.skip when input stream reads from a ReadableByteChannel. + */ + @Test + void testReadableByteChannel() throws Exception { + final int size = 10; + byte[] bytes = "X".repeat(size).getBytes("UTF-8"); + + var ch = new ReadableByteChannel() { + private final ByteBuffer src = ByteBuffer.wrap(bytes); + @Override + public int read(ByteBuffer dst) { + if (!dst.hasRemaining()) + return 0; + if (!src.hasRemaining()) + return -1; + int n = Math.min(src.remaining(), dst.remaining()); + dst.put(src.array(), src.position(), n); + src.position(src.position() + n); + return n; + } + @Override + public boolean isOpen() { + return true; + } + @Override + public void close() throws IOException { + throw new IOException(); + } + }; + + InputStream in = Channels.newInputStream(ch); + assertEquals(0L, in.skip(-1)); + assertEquals(0L, in.skip(0)); + + int remaining = size; + for (int n = 1; n <= 3; n++) { + assertEquals(n, in.skip(n)); + remaining -= n; + } + assertTrue(remaining >= 0); + assertEquals(remaining, in.skip(100)); + assertEquals(0, in.skip(100)); + } + + /** + * Test InputStream.skip when input stream reads from a socket. + * @param in input stream that reads from a socket + * @param peer output stream of connected peer + */ + void testSocketInputStreamSkip(InputStream in, OutputStream peer) throws Exception { + assertEquals(0L, in.skip(-1)); + assertEquals(0L, in.skip(0)); + + final int count = 10; + peer.write("X".repeat(count).getBytes("UTF-8")); + + assertEquals(0L, in.skip(-1)); + assertEquals(0L, in.skip(0)); + + // consume bytes + int remaining = count; + for (int n = 1; n <= 3; n++) { + assertEquals(n, in.skip(n)); + remaining -= n; + } + assertTrue(remaining >= 0); + + assertEquals(0L, in.skip(0)); + + peer.close(); + + assertEquals(remaining, in.skip(100)); + assertEquals(0, in.skip(100)); + } + + /** + * Test InputStream.skip for input stream that reads from a socket channel. + */ + @Test + void testSocketChannel() throws Exception { + try (var connection = new Connection()) { + InputStream in = Channels.newInputStream(connection.channel1()); + OutputStream out = Channels.newOutputStream(connection.channel2()); + testSocketInputStreamSkip(in, out); + } + } + + /** + * Test InputStream.skip for input stream that reads from a socket associated + * with a socket channel. + */ + @Test + void testSocketChannelAdaptor() throws Exception { + try (var connection = new Connection()) { + Socket s1 = connection.channel1().socket(); + Socket s2 = connection.channel2().socket(); + testSocketInputStreamSkip(s1.getInputStream(), s2.getOutputStream()); + } + } + + /** + * A loopback connection. + */ + private static class Connection implements Closeable { + private final SocketChannel sc1; + private final SocketChannel sc2; + Connection() throws IOException { + var lh = InetAddress.getLoopbackAddress(); + try (var listener = ServerSocketChannel.open()) { + listener.bind(new InetSocketAddress(lh, 0)); + SocketChannel sc1 = SocketChannel.open(); + SocketChannel sc2 = null; + try { + sc1.socket().connect(listener.getLocalAddress()); + sc2 = listener.accept(); + } catch (IOException ioe) { + sc1.close(); + throw ioe; + } + this.sc1 = sc1; + this.sc2 = sc2; + } + } + SocketChannel channel1() { + return sc1; + } + SocketChannel channel2() { + return sc2; + } + @Override + public void close() throws IOException { + sc1.close(); + sc2.close(); + } + } +} diff --git a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java index 7e9343018927..2514dd582e89 100644 --- a/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java +++ b/test/jdk/java/nio/channels/vthread/BlockingChannelOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, 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,26 +23,33 @@ /* * @test id=default - * @bug 8284161 + * @bug 8284161 8394217 * @summary Test virtual threads doing blocking I/O on NIO channels * @library /test/lib - * @run junit/timeout=480 BlockingChannelOps + * @run junit/timeout=480 ${test.main.class} */ /* * @test id=poller-modes * @requires (os.family == "linux") | (os.family == "mac") * @library /test/lib - * @run junit/othervm/timeout=480 -Djdk.pollerMode=1 BlockingChannelOps - * @run junit/othervm/timeout=480 -Djdk.pollerMode=2 BlockingChannelOps - * @run junit/othervm/timeout=480 -Djdk.pollerMode=3 BlockingChannelOps + * @run junit/othervm/timeout=480 -Djdk.pollerMode=1 ${test.main.class} + * @run junit/othervm/timeout=480 -Djdk.pollerMode=2 ${test.main.class} + * @run junit/othervm/timeout=480 -Djdk.pollerMode=3 ${test.main.class} + */ + +/* + * @test id=no-write-poller-thread + * @requires (os.family == "linux") | (os.family == "mac") + * @library /test/lib + * @run junit/othervm/timeout=480 -Djdk.pollerMode=1 -Djdk.writePollers=0 ${test.main.class} */ /* * @test id=no-vmcontinuations * @requires vm.continuations * @library /test/lib - * @run junit/othervm/timeout=480 -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations BlockingChannelOps + * @run junit/othervm/timeout=480 -XX:+UnlockExperimentalVMOptions -XX:-VMContinuations ${test.main.class} */ import java.io.Closeable; diff --git a/test/jdk/java/nio/file/Files/StreamLinesTest.java b/test/jdk/java/nio/file/Files/StreamLinesTest.java index 7812a4ceb893..ac5d0e70e2b2 100644 --- a/test/jdk/java/nio/file/Files/StreamLinesTest.java +++ b/test/jdk/java/nio/file/Files/StreamLinesTest.java @@ -22,7 +22,7 @@ */ /* @test - * @bug 8072773 + * @bug 8072773 8393016 * @library /test/lib * @build jdk.test.lib.RandomFactory * @run junit/othervm StreamLinesTest @@ -46,6 +46,8 @@ import java.util.EnumSet; import java.util.List; import java.util.Random; +import java.util.Spliterator; +import java.util.function.Consumer; import java.util.function.IntFunction; import java.util.stream.Stream; import jdk.test.lib.RandomFactory; @@ -53,8 +55,11 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; public class StreamLinesTest { @@ -196,4 +201,42 @@ public void test(IntFunction lineGenerator, IntFunction s assertEquals(expected, s.toList()); } } + + @ParameterizedTest + @ValueSource(ints = {0, 2, 5}) + void testTryAdvanceNullAction(int consumed) throws IOException { + testNullAction(consumed, sp -> sp.tryAdvance(null)); + } + + @ParameterizedTest + @ValueSource(ints = {0, 2, 5}) + void testForEachRemainingNullAction(int consumed) throws IOException { + testNullAction(consumed, sp -> sp.forEachRemaining(null)); + } + + private void testNullAction( + int consumed, + Consumer> operation) throws IOException { + + List lines = List.of("L0", "L1", "L2", "L3", "L4"); + Path file = generateTempFileWithLines( + i -> "L" + i, i -> LineSeparator.N, lines.size(), + StandardCharsets.UTF_8, false); + + try (Stream stream = Files.lines(file, StandardCharsets.UTF_8)) { + Spliterator sp = stream.spliterator(); + + // Consume some lines first + for (int i = 0; i < consumed; i++) { + assertTrue(sp.tryAdvance(l -> { })); + } + + assertThrows(NullPointerException.class, () -> operation.accept(sp)); + + // Verify that the remaining lines are still available + List remaining = new ArrayList<>(); + sp.forEachRemaining(remaining::add); + assertEquals(lines.subList(consumed, lines.size()), remaining); + } + } } diff --git a/test/jdk/java/text/Format/DateFormat/CustomZoneTest.java b/test/jdk/java/text/Format/DateFormat/ExplicitDstOffsetTest.java similarity index 54% rename from test/jdk/java/text/Format/DateFormat/CustomZoneTest.java rename to test/jdk/java/text/Format/DateFormat/ExplicitDstOffsetTest.java index 87ec0577abb3..27c7fdced603 100644 --- a/test/jdk/java/text/Format/DateFormat/CustomZoneTest.java +++ b/test/jdk/java/text/Format/DateFormat/ExplicitDstOffsetTest.java @@ -23,21 +23,27 @@ /* * @test - * @bug 8392995 + * @bug 8392995 8392991 * @summary Ensure that a custom time zone does not look up CLDR metazone data via * an explicit offset for daylight names during SimpleDateFormat formatting. Only - * a canonical JDK TimeZone should defer to the metazone data in such cases. - * @run junit CustomZoneTest + * a canonical JDK TimeZone should defer to the metazone data in such cases. Parsing + * should consult the explicit dstOffset of a zone when it exists. + * @run junit ExplicitDstOffsetTest */ import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.FieldSource; import java.text.DateFormatSymbols; +import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.Instant; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.Date; +import java.util.List; import java.util.Locale; import java.util.SimpleTimeZone; import java.util.TimeZone; @@ -45,11 +51,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; // Any fixed standard strings correspond to CLDR data as of v48.2 -public class CustomZoneTest { +public class ExplicitDstOffsetTest { private static final String AMERICA_VANCOUVER = "America/Vancouver"; + private static final String EUROPE_DUBLIN = "Europe/Dublin"; private static final TimeZone JDK_AMERICA_VANCOUVER = TimeZone.getTimeZone(AMERICA_VANCOUVER); + private static final TimeZone JDK_EUROPE_DUBLIN = + TimeZone.getTimeZone(EUROPE_DUBLIN); // Fixed raw offset (that mimics daylight savings for America/Vancouver) // but in actuality has no daylight savings rules and is named "America/Vancouver". @@ -137,4 +146,88 @@ void modifiedStandardZoneTest() { assertEquals("Pacific Daylight Time", format.format( Date.from(Instant.parse("2020-07-01T12:00:00Z")))); } + + // These instants are formatted/parsed under Europe/Dublin + private static final List EXPLICIT_DST_OFFSET_DATES = List.of( + // Historical daylight offset: +00:34:39 + Date.from(Instant.parse("1916-07-15T00:00:00Z")), + // Formats to -> 1916-07-15 00:34:39 Greenwich Mean Time + // ------------- + // Historical standard offset: −00:25:21 + Date.from(Instant.parse("1916-01-15T00:00:00Z")), + // Formats to -> 1916-01-14 23:34:39 Greenwich Mean Time + // ------------- + // Modern daylight offset: +01:00 + Date.from(Instant.parse("2026-04-04T23:00:00Z")), + // Formats to -> 2026-04-05 00:00:00 Irish Standard Time + // ------------- + // Modern standard offset: +00:00 + Date.from(Instant.parse("2026-12-05T00:00:00Z")), + // Formats to -> 2026-12-05 00:00:00 Greenwich Mean Time + //-------------- + // Test dates at the dst/std transition period + // Dublin transitions on 10/25 at 2:00 AM + // During daylight + Date.from(Instant.parse("2026-10-25T00:30:00Z")), + // Formats to 2026-10-25 01:30:00 Irish Standard Time + // During standard + Date.from(Instant.parse("2026-10-25T01:30:00Z")) + ); + + // Europe/Dublin uses explicit dstOffset. For such cases, the zone should be used to derive the offset + // at the given date. When the date is during a transition period, then the matched name can be used + // as a tiebreaker. This contrasts from normal parsing, which prefers using the matched name to determine + // the offset. + @ParameterizedTest + @FieldSource("EXPLICIT_DST_OFFSET_DATES") + void dstOffsetRoundTripParsingTest(Date before) throws ParseException { + var format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss zzzz", Locale.US); + format.setTimeZone(JDK_EUROPE_DUBLIN); + String text = format.format(before); + Date after = format.parse(text); + assertEquals(before, after, "explicit dstOffset zone did not round trip correctly"); + } + + // These instants are formatted/parsed under Europe/Dublin + private static final List EXPLICIT_DST_OFFSET_CONFLICTING_PATTERN_DATES = List.of( + // Even though the text is in a transition period, which indicates the name should be + // used to dictate std time, the explicit numeric offset should take precedence and produce the + // resultant date in dst. + Arguments.of("yyyy-MM-dd HH:mm:ss zzzz XXX", + "2026-10-25 01:30:00 Greenwich Mean Time +01:00", + Date.from(Instant.parse("2026-10-25T00:30:00Z"))), + // Same as above, but in the other direction + Arguments.of("yyyy-MM-dd HH:mm:ss XXX zzzz", + "2026-10-25 01:30:00 +01:00 Greenwich Mean Time", + Date.from(Instant.parse("2026-10-25T01:30:00Z"))) + ); + + // Ensure that the new explicit dstOffset behavior during ambiguous transition period does not conflict + // with a subsequent time zone pattern and vice versa. Latest should always win. + @ParameterizedTest + @FieldSource("EXPLICIT_DST_OFFSET_CONFLICTING_PATTERN_DATES") + void dstOffsetConflictingZonesTest(String pattern, String text, Date date) throws ParseException { + var format = new SimpleDateFormat(pattern, Locale.US); + format.setTimeZone(JDK_EUROPE_DUBLIN); + var parsed = format.parse(text); + assertEquals(date, parsed, "Pattern precedence incorrect for explicit dstOffset"); + } + + // Ensure that explicit dstOffset is taken into account even on century changes. + @Test + void dstOffsetCenturyTest() throws ParseException { + var format = new SimpleDateFormat("yy-MM-dd HH:mm:ss zzzz", Locale.US); + format.setTimeZone(JDK_EUROPE_DUBLIN); + format.set2DigitYearStart(Date.from(Instant.parse("2026-10-28T00:00:00Z"))); + var before = Date.from(Instant.parse("2126-10-27T00:30:00Z")); + var formatted = format.format(before); + // Formats as -> 26-10-27 01:30:00 Irish Standard Time + // When we parse it, 2026/10/27 is before the century start, so 100 years is incremented. + // This moves the new date to 2126-10-27 01:30:00 Irish Standard Time. This lands + // on a transition date, and we need to use the Irish Standard Time naming to determine + // the appropriate offset. Otherwise, the calendar would default to the standard time, + // and the date produced would be "2126-10-27T01:30:00Z" + assertEquals(before, format.parse(formatted), + "explicit dstOffset not taken into account for next century"); + } } diff --git a/test/jdk/java/util/Arrays/ArrayObjectMethods.java b/test/jdk/java/util/Arrays/ArrayObjectMethods.java index a33b399bfdf9..edcbb69e2c82 100644 --- a/test/jdk/java/util/Arrays/ArrayObjectMethods.java +++ b/test/jdk/java/util/Arrays/ArrayObjectMethods.java @@ -28,6 +28,7 @@ * @author Josh Bloch, Martin Buchholz * @key randomness * @library /test/lib + * @run main/othervm -Xmx64m ${test.main.class} */ import java.util.*; diff --git a/test/jdk/java/util/Arrays/SortingNearlySortedPrimitive.java b/test/jdk/java/util/Arrays/SortingNearlySortedPrimitive.java index b9ad458688e3..51440ca5eeb1 100644 --- a/test/jdk/java/util/Arrays/SortingNearlySortedPrimitive.java +++ b/test/jdk/java/util/Arrays/SortingNearlySortedPrimitive.java @@ -29,8 +29,7 @@ * code that detects patterns in the array to determine if it is nearly * sorted and if so employs and optimizes merge sort rather than a * Dual-Pivot QuickSort. - * - * @run junit SortingNearlySortedPrimitive + * @run junit/othervm -Xmx64m SortingNearlySortedPrimitive */ diff --git a/test/jdk/javax/net/ssl/ExtendedSSLSession/NamedGroupTestData.java b/test/jdk/javax/net/ssl/ExtendedSSLSession/NamedGroupTestData.java new file mode 100644 index 000000000000..0065d802beb4 --- /dev/null +++ b/test/jdk/javax/net/ssl/ExtendedSSLSession/NamedGroupTestData.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2026, 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 data class, not a test. +final class NamedGroupTestData { + + static final String[] DEFAULT_SUPPORTED_NG = new String[]{ + "X25519MLKEM768", + "x25519", + "secp256r1", + "secp384r1", + "secp521r1", + "x448", + "ffdhe2048", + "ffdhe3072", + "ffdhe4096", + "sect233k1", + "sect233r1", + "sect239k1", + "sect283k1", + "sect283r1", + "sect409k1", + "sect409r1", + "sect571k1", + "sect571r1", + "secp224k1", + "secp224r1", + "secp256k1", + "ffdhe6144", + "ffdhe8192", + "SecP256r1MLKEM768", + "SecP384r1MLKEM1024" + }; + + // X25519MLKEM768, SecP256r1MLKEM768 and SecP384r1MLKEM1024 are not + // supported in DTLSv1.2 + static final String[] DTLS12_SUPPORTED_NG = new String[]{ + "x25519", + "secp256r1", + "secp384r1", + "secp521r1", + "x448", + "ffdhe2048", + "ffdhe3072", + "ffdhe4096", + "sect233k1", + "sect233r1", + "sect239k1", + "sect283k1", + "sect283r1", + "sect409k1", + "sect409r1", + "sect571k1", + "sect571r1", + "secp224k1", + "secp224r1", + "secp256k1", + "ffdhe6144", + "ffdhe8192" + }; + + static final String[][] TEST_VALUES = new String[][]{ + /* + * Test values format as follows: + * Requested Named Group(s), Negotiated Named Group, Protocol + */ + + // Use default named group + {null, "X25519MLKEM768", "TLSv1.3"}, + {null, "x25519", "TLSv1.2"}, + {null, "x25519", "DTLSv1.2"}, + + // Request a single named group + {"secp384r1", "secp384r1", "TLSv1.3"}, + {"secp384r1", "secp384r1", "TLSv1.2"}, + {"secp384r1", "secp384r1", "DTLSv1.2"}, + + // Request multiple named groups + {"secp256r1,secp384r1", "secp256r1", "TLSv1.3"}, + {"secp256r1,secp384r1", "secp256r1", "TLSv1.2"}, + {"secp256r1,secp384r1", "secp256r1", "DTLSv1.2"}, + }; +} diff --git a/test/jdk/javax/net/ssl/ExtendedSSLSession/SSLEngineNegotiatedSupportedNamedGroup.java b/test/jdk/javax/net/ssl/ExtendedSSLSession/SSLEngineNegotiatedSupportedNamedGroup.java new file mode 100644 index 000000000000..fe8846b4a024 --- /dev/null +++ b/test/jdk/javax/net/ssl/ExtendedSSLSession/SSLEngineNegotiatedSupportedNamedGroup.java @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2026, 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. + */ + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertTrue; + +import java.nio.ByteBuffer; +import java.util.Arrays; +import javax.net.ssl.ExtendedSSLSession; +import javax.net.ssl.SSLEngine; +import javax.net.ssl.SSLEngineResult; +import javax.net.ssl.SSLEngineResult.HandshakeStatus; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLSession; + +/* + * @test + * @bug 8388519 + * @summary Verify that ExtendedSSLSession reports the negotiated named group. + * Verify that SSLEngine reports the supported named groups. + * @library /javax/net/ssl/templates + * /test/lib + * @build NamedGroupTestData + * @run main SSLEngineNegotiatedSupportedNamedGroup + */ + +public class SSLEngineNegotiatedSupportedNamedGroup extends SSLEngineTemplate { + private static String protocol; + + private final String[] inputNamedGroups; + private final String negotiatedNamedGroup; + + protected SSLEngineNegotiatedSupportedNamedGroup(String[] inputNamedGroups, + String negotiatedNamedGroup) throws Exception { + this.inputNamedGroups = inputNamedGroups; + this.negotiatedNamedGroup = negotiatedNamedGroup; + } + + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters(protocol, "PKIX", "SunX509"); + } + + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters(protocol, "PKIX", "SunX509"); + } + + public static void main(String[] args) throws Exception { + // Run through test values + for (String[] v : NamedGroupTestData.TEST_VALUES) { + System.out.println("Running with test parameters: " + + Arrays.toString(v)); + protocol = v[2]; + new SSLEngineNegotiatedSupportedNamedGroup( + v[0] != null ? v[0].split(",") : null, + v[1]).run(); + } + } + + private void run() throws Exception { + for (SSLEngine engine : new SSLEngine[]{serverEngine, clientEngine}) { + SSLParameters params = engine.getSSLParameters(); + params.setProtocols(new String[]{protocol}); + params.setNamedGroups(inputNamedGroups); + engine.setSSLParameters(params); + } + + // Complete handshake. + initialSession(clientEngine, serverEngine); + + checkNamedGroup(serverEngine); + checkNamedGroup(clientEngine); + } + + private void checkNamedGroup(SSLEngine engine) { + // Check SSLEngine.getSupportedNamedGroups() call + assertTrue(Arrays.equals(getDefaultSupportedGroups(), + engine.getSupportedNamedGroups()), "Expected: " + + Arrays.toString(getDefaultSupportedGroups()) + + "; Received: " + + Arrays.toString(engine.getSupportedNamedGroups())); + + // Check ExtendedSSLSession.getNamedGroup() call + ExtendedSSLSession session = + (ExtendedSSLSession) engine.getSession(); + assertEquals(negotiatedNamedGroup, session.getNamedGroup()); + } + + private static String[] getDefaultSupportedGroups() { + if (protocol.equals("DTLSv1.2")) { + return NamedGroupTestData.DTLS12_SUPPORTED_NG; + } else { + return NamedGroupTestData.DEFAULT_SUPPORTED_NG; + } + } + + // Works for both TLS and DTLS. + private static void initialSession(SSLEngine clientEngine, + SSLEngine serverEngine) throws SSLException { + boolean clientDone = false; + boolean serverDone = false; + boolean cliDataReady = false; + boolean servDataReady = false; + SSLEngineResult clientResult; + SSLEngineResult serverResult; + SSLSession session = clientEngine.getSession(); + int appBufferMax = session.getApplicationBufferSize(); + int netBufferMax = session.getPacketBufferSize(); + ByteBuffer clientIn = ByteBuffer.allocate(appBufferMax + 50); + ByteBuffer serverIn = ByteBuffer.allocate(appBufferMax + 50); + ByteBuffer cTOs = ByteBuffer.allocateDirect(netBufferMax); + ByteBuffer sTOc = ByteBuffer.allocateDirect(netBufferMax); + HandshakeStatus hsStat; + final ByteBuffer clientOut = ByteBuffer.wrap( + "Hi Server, I'm Client".getBytes()); + final ByteBuffer serverOut = ByteBuffer.wrap( + "Hello Client, I'm Server".getBytes()); + + clientEngine.beginHandshake(); + serverEngine.beginHandshake(); + + while (!clientDone && !serverDone) { + // Client processing + hsStat = clientEngine.getHandshakeStatus(); + log("Client HS Stat: " + hsStat); + switch (hsStat) { + case NOT_HANDSHAKING: + log("Closing client engine"); + clientEngine.closeOutbound(); + clientDone = true; + break; + case NEED_WRAP: + log(String.format("CTOS: p:%d, l:%d, c:%d", cTOs.position(), + cTOs.limit(), cTOs.capacity())); + clientResult = clientEngine.wrap(clientOut, cTOs); + log("client wrap: ", clientResult); + if (clientResult.getStatus() + == SSLEngineResult.Status.BUFFER_OVERFLOW) { + // Get a larger buffer and try again + int updateSize = 2 * netBufferMax; + log("Resizing buffer to " + updateSize + " bytes"); + cTOs = ByteBuffer.allocate(updateSize); + clientResult = clientEngine.wrap(clientOut, cTOs); + log("client wrap (resized): ", clientResult); + } + runDelegatedTasks(clientResult, clientEngine); + cTOs.flip(); + cliDataReady = true; + break; + case NEED_UNWRAP: + if (servDataReady) { + log(String.format("STOC: p:%d, l:%d, c:%d", + sTOc.position(), + sTOc.limit(), sTOc.capacity())); + clientResult = clientEngine.unwrap(sTOc, clientIn); + log("client unwrap: ", clientResult); + runDelegatedTasks(clientResult, clientEngine); + servDataReady = sTOc.hasRemaining(); + sTOc.compact(); + } else { + log("Server-to-client data not ready, skipping client" + + " unwrap"); + } + break; + case NEED_UNWRAP_AGAIN: + clientResult = clientEngine.unwrap(ByteBuffer.allocate(0), + clientIn); + log("client unwrap (again): ", clientResult); + runDelegatedTasks(clientResult, clientEngine); + break; + } + + // Server processing + hsStat = serverEngine.getHandshakeStatus(); + log("Server HS Stat: " + hsStat); + switch (hsStat) { + case NEED_WRAP: + log(String.format("STOC: p:%d, l:%d, c:%d", sTOc.position(), + sTOc.limit(), sTOc.capacity())); + serverResult = serverEngine.wrap(serverOut, sTOc); + log("server wrap: ", serverResult); + if (serverResult.getStatus() + == SSLEngineResult.Status.BUFFER_OVERFLOW) { + // Get a new buffer and try again + int updateSize = 2 * netBufferMax; + log("Resizing buffer to " + updateSize + " bytes"); + sTOc = ByteBuffer.allocate(updateSize); + serverResult = serverEngine.wrap(clientOut, sTOc); + log("server wrap (resized): ", serverResult); + } + runDelegatedTasks(serverResult, serverEngine); + sTOc.flip(); + servDataReady = true; + break; + case NOT_HANDSHAKING: + log("Closing server engine"); + serverEngine.closeOutbound(); + serverDone = true; + break; + case NEED_UNWRAP: + if (cliDataReady) { + log(String.format("CTOS: p:%d, l:%d, c:%d", + cTOs.position(), + cTOs.limit(), cTOs.capacity())); + serverResult = serverEngine.unwrap(cTOs, serverIn); + log("server unwrap: ", serverResult); + runDelegatedTasks(serverResult, serverEngine); + cliDataReady = cTOs.hasRemaining(); + cTOs.compact(); + } else { + log("Client-to-server data not ready, skipping server" + + " unwrap"); + } + break; + case NEED_UNWRAP_AGAIN: + serverResult = serverEngine.unwrap(ByteBuffer.allocate(0), + serverIn); + log("server unwrap (again): ", serverResult); + runDelegatedTasks(serverResult, serverEngine); + break; + } + } + } + + private static void log(String str) { + System.out.println(str); + } + + private static void log(String str, SSLEngineResult result) { + System.out.println("The format of the SSLEngineResult is: \n" + + "\t\"getStatus() / getHandshakeStatus()\" +\n" + + "\t\"bytesConsumed() / bytesProduced()\"\n"); + + HandshakeStatus hsStatus = result.getHandshakeStatus(); + + log(str + + result.getStatus() + "/" + hsStatus + ", " + + result.bytesConsumed() + "/" + result.bytesProduced() + + " bytes"); + + if (hsStatus == HandshakeStatus.FINISHED) { + log("\t...ready for application data"); + } + } + + private static void runDelegatedTasks(SSLEngineResult result, + SSLEngine engine) { + HandshakeStatus hsStatus = result.getHandshakeStatus(); + + if (hsStatus == HandshakeStatus.NEED_TASK) { + Runnable runnable; + while ((runnable = engine.getDelegatedTask()) != null) { + log("\trunning delegated task..."); + runnable.run(); + } + hsStatus = engine.getHandshakeStatus(); + if (hsStatus == HandshakeStatus.NEED_TASK) { + throw new RuntimeException( + "handshake shouldn't need additional tasks"); + } + log("\tnew HandshakeStatus: " + hsStatus); + } + } +} diff --git a/test/jdk/javax/net/ssl/ExtendedSSLSession/SSLSocketNegotiatedSupportedNamedGroup.java b/test/jdk/javax/net/ssl/ExtendedSSLSession/SSLSocketNegotiatedSupportedNamedGroup.java new file mode 100644 index 000000000000..b9f9af655a57 --- /dev/null +++ b/test/jdk/javax/net/ssl/ExtendedSSLSession/SSLSocketNegotiatedSupportedNamedGroup.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2026, 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. + */ + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertTrue; + +import java.net.InetSocketAddress; +import java.util.Arrays; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import javax.net.ssl.ExtendedSSLSession; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLParameters; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; + +/* + * @test + * @bug 8388519 + * @summary Verify that ExtendedSSLSession reports the negotiated named group. + * Verify that SSLSocket reports the supported named groups. + * @library /javax/net/ssl/templates + * /test/lib + * @build NamedGroupTestData + * + * @comment Full Handshake + * @run main SSLSocketNegotiatedSupportedNamedGroup + * + * @comment Stateless Resumption + * @run main SSLSocketNegotiatedSupportedNamedGroup resume TLSv1.3 + * @run main SSLSocketNegotiatedSupportedNamedGroup resume TLSv1.2 + * + * @comment Stateful Resumption + * @run main/othervm -Djdk.tls.server.enableSessionTicketExtension=false + * SSLSocketNegotiatedSupportedNamedGroup resume TLSv1.3 + * @run main/othervm -Djdk.tls.server.enableSessionTicketExtension=false + * SSLSocketNegotiatedSupportedNamedGroup resume TLSv1.2 + */ + +public class SSLSocketNegotiatedSupportedNamedGroup extends SSLSocketTemplate { + + private static final String INITIAL_GROUP = "secp256r1"; + private static final String RESUMED_GROUP = "secp384r1"; + private static final int TIMEOUT = 20000; + + private final String[] inputNamedGroups; + private final String negotiatedNamedGroup; + private final String protocol; + + public SSLSocketNegotiatedSupportedNamedGroup(String[] inputNamedGroups, + String negotiatedNamedGroup, String protocol) { + this.inputNamedGroups = inputNamedGroups; + this.negotiatedNamedGroup = negotiatedNamedGroup; + this.protocol = protocol; + } + + @Override + protected ContextParameters getClientContextParameters() { + return new ContextParameters(protocol, "PKIX", "SunX509"); + } + + @Override + protected ContextParameters getServerContextParameters() { + return new ContextParameters(protocol, "PKIX", "SunX509"); + } + + public static void main(String[] args) throws Exception { + if (args.length > 0 && args[0].equals("resume")) { + new SSLSocketNegotiatedSupportedNamedGroup( + null, null, args[1]).testResumption(); + return; + } + + runFullHandshakeTests(); + } + + private static void runFullHandshakeTests() throws Exception { + // Check SSLServerSocket.getSupportedNamedGroups() call with default + // configuration. + SSLSocketTemplate defaultTest = new SSLSocketTemplate(); + SSLContext context = defaultTest.createServerSSLContext(); + SSLServerSocketFactory sslssf = context.getServerSocketFactory(); + try (SSLServerSocket sslServerSocket = + (SSLServerSocket) sslssf.createServerSocket( + defaultTest.serverPort, 0, defaultTest.serverAddress)) { + assertTrue(Arrays.equals(NamedGroupTestData.DEFAULT_SUPPORTED_NG, + sslServerSocket.getSupportedNamedGroups()), + Arrays.toString(sslServerSocket.getSupportedNamedGroups())); + } + + // Run through test values + for (String[] v : NamedGroupTestData.TEST_VALUES) { + // SSLSocket doesn't support DTLS + if (!v[2].startsWith("DTLS")) { + System.out.println("Running with test parameters: " + + Arrays.toString(v)); + new SSLSocketNegotiatedSupportedNamedGroup( + v[0] != null ? v[0].split(",") : null, + v[1], v[2]).run(); + } + } + } + + @Override + protected void configureServerSocket(SSLServerSocket socket) { + SSLParameters params = socket.getSSLParameters(); + params.setProtocols(new String[]{protocol}); + params.setNamedGroups(inputNamedGroups); + socket.setSSLParameters(params); + } + + @Override + protected void configureClientSocket(SSLSocket socket) { + SSLParameters params = socket.getSSLParameters(); + params.setProtocols(new String[]{protocol}); + params.setNamedGroups(inputNamedGroups); + socket.setSSLParameters(params); + } + + @Override + protected void runServerApplication(SSLSocket socket) throws Exception { + super.runServerApplication(socket); + checkNamedGroup(socket); + } + + @Override + protected void runClientApplication(SSLSocket socket) throws Exception { + super.runClientApplication(socket); + checkNamedGroup(socket); + } + + private void checkNamedGroup(SSLSocket socket) { + // Check SSLSocket.getSupportedNamedGroups() call + assertTrue(Arrays.equals(NamedGroupTestData.DEFAULT_SUPPORTED_NG, + socket.getSupportedNamedGroups()), "Expected: " + + Arrays.toString(NamedGroupTestData.DEFAULT_SUPPORTED_NG) + + "; Received: " + + Arrays.toString(socket.getSupportedNamedGroups())); + + // Check ExtendedSSLSession.getNamedGroup() call + ExtendedSSLSession session = + (ExtendedSSLSession) socket.getSession(); + assertEquals(negotiatedNamedGroup, session.getNamedGroup()); + } + + // Resumption test entry point. + private void testResumption() throws Exception { + // Key exchange is not performed in TLSv1.2 resumption unlike in TLSv1.3, + // so getNamedGroup() returns null for a resumed TLSv1.2 session. + String resumedNamedGroup = protocol.equals("TLSv1.3") ? + RESUMED_GROUP : null; + + SSLContext serverContext = createServerSSLContext(); + SSLContext clientContext = createClientSSLContext(); + + try (SSLServerSocket serverSocket = (SSLServerSocket) + serverContext.getServerSocketFactory().createServerSocket( + 0, 0, serverAddress); + ExecutorService executor = Executors.newSingleThreadExecutor()) { + + configureResumptionServerSocket(serverSocket); + serverSocket.setSoTimeout(TIMEOUT); + + // Start server. + Future serverFuture = executor.submit(() -> { + runServer(serverSocket, resumedNamedGroup); + return null; + }); + + // Run initial client. + long initialCreationTime = runClient( + clientContext, serverSocket.getLocalPort(), + INITIAL_GROUP, INITIAL_GROUP, false); + + // Run resumption client. + long resumedCreationTime = runClient( + clientContext, serverSocket.getLocalPort(), + RESUMED_GROUP, resumedNamedGroup, true); + + assertTrue(initialCreationTime == resumedCreationTime, + "Client session was not resumed"); + serverFuture.get(); + } + } + + private void configureResumptionServerSocket(SSLServerSocket socket) { + SSLParameters params = socket.getSSLParameters(); + params.setProtocols(new String[]{protocol}); + params.setNamedGroups(new String[]{INITIAL_GROUP, RESUMED_GROUP}); + socket.setSSLParameters(params); + } + + private void runServer(SSLServerSocket serverSocket, + String resumedNamedGroup) throws Exception { + + long initialCreationTime = 0; + String[] expectedNamedGroups = { + INITIAL_GROUP, resumedNamedGroup}; + + for (int i = 0; i < expectedNamedGroups.length; i++) { + try (SSLSocket socket = (SSLSocket) serverSocket.accept()) { + socket.setSoTimeout(TIMEOUT); + + // Don't create a new session on 2nd connection. + if (i == 1) { + socket.setEnableSessionCreation(false); + } + + socket.startHandshake(); + ExtendedSSLSession session = + (ExtendedSSLSession) socket.getSession(); + + assertEquals(expectedNamedGroups[i], + session.getNamedGroup()); + + if (i == 0) { + initialCreationTime = session.getCreationTime(); + } else { + assertTrue(initialCreationTime == session.getCreationTime(), + "Server session was not resumed"); + } + + socket.getInputStream().read(); + socket.getOutputStream().write(280); + socket.getOutputStream().flush(); + } + } + } + + private long runClient(SSLContext context, int serverPort, + String namedGroup, String expectedNamedGroup, + boolean resume) throws Exception { + + try (SSLSocket socket = + (SSLSocket) context.getSocketFactory().createSocket()) { + + SSLParameters params = socket.getSSLParameters(); + params.setProtocols(new String[]{protocol}); + params.setNamedGroups(new String[]{namedGroup}); + socket.setSSLParameters(params); + socket.setSoTimeout(TIMEOUT); + + if (resume) { + socket.setEnableSessionCreation(false); + } + + socket.connect(new InetSocketAddress(serverAddress, serverPort), + TIMEOUT); + socket.startHandshake(); + + ExtendedSSLSession session = (ExtendedSSLSession) socket.getSession(); + assertEquals(expectedNamedGroup, session.getNamedGroup()); + + socket.getOutputStream().write(85); + socket.getOutputStream().flush(); + socket.getInputStream().read(); + + return session.getCreationTime(); + } + } +} diff --git a/test/jdk/jdk/internal/platform/docker/MetricsMemoryTester.java b/test/jdk/jdk/internal/platform/docker/MetricsMemoryTester.java index 53924b6abadb..7306b7219376 100644 --- a/test/jdk/jdk/internal/platform/docker/MetricsMemoryTester.java +++ b/test/jdk/jdk/internal/platform/docker/MetricsMemoryTester.java @@ -87,10 +87,10 @@ private static void testMemoryFailCount() { System.out.println("Initial memory fail count: " + initialFailCount); - // Allocate 512M of data in 1M chunks per iteration - byte[][] bytes = new byte[512][]; + // Allocate up to 256M of data in 1M chunks, two G1 regions per chunk at this heap size + byte[][] bytes = new byte[256][]; - for (int i = 0; i < 512; i++) { + for (int i = 0; i < bytes.length; i++) { if (i % 8 == 0) { System.out.printf("Allocated: %3dM, Memory usage: %3dM, Memory and swap: %3dM\n", i, @@ -113,6 +113,13 @@ private static void testMemoryFailCount() { System.out.println("Final memory fail count: " + newCount); if (newCount <= initialFailCount) { + // A limiting ancestor may account for events not visible in this cgroup. + if (initialFailCount >= 0 && newCount == initialFailCount + && memLimit > 0 && metrics.getMemoryAndSwapUsage() > memLimit) { + System.out.println("Memory and swap usage exceeds the memory limit, " + + "but the fail count is unchanged. Ignoring test!"); + return; + } throw new RuntimeException("Memory fail count did not increase: initial=" + initialFailCount + ", final=" + newCount); } diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java index 32b8661379f5..65a534f12860 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/CAInterop.java @@ -559,6 +559,34 @@ * wisekeyglobalrootgcca CRL */ +/* + * @test id=certumtrustedrootca + * @bug 8392771 + * @summary Interoperability tests with Certum Trusted Root CA + * @library /test/lib + * @build jtreg.SkippedException ValidatePathWithURL CAInterop + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop + * certumtrustedrootca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp + * -Dcom.sun.security.ocsp.useget=false CAInterop certumtrustedrootca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop + * certumtrustedrootca CRL + */ + +/* + * @test id=certumec384ca + * @bug 8392771 + * @summary Interoperability tests with Certum EC-384 CA + * @library /test/lib + * @build jtreg.SkippedException ValidatePathWithURL CAInterop + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp CAInterop + * certumec384ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath,ocsp + * -Dcom.sun.security.ocsp.useget=false CAInterop certumec384ca OCSP + * @run main/othervm/manual -Djava.security.debug=certpath CAInterop + * certumec384ca CRL + */ + /** * Collection of certificate validation tests for interoperability with external CAs. * These tests are marked as manual as they depend on external infrastructure and may fail @@ -741,6 +769,13 @@ private CATestURLs getTestURLs(String alias) { new CATestURLs("https://gcvalidssl.hightrusted.com", "https://gcrevokedssl.hightrusted.com"); + case "certumtrustedrootca" -> + new CATestURLs("https://valid-ctrca.certificates.certum.pl", + "https://revoked-ctrca.certificates.certum.pl"); + case "certumec384ca" -> + new CATestURLs("https://valid-cec384ca.certificates.certum.pl", + "https://revoked-cec384ca.certificates.certum.pl"); + default -> throw new RuntimeException("No test setup found for: " + alias); }; } diff --git a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java index 14e48a6e78fb..60c2066e1345 100644 --- a/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java +++ b/test/jdk/security/infra/java/security/cert/CertPathValidator/certification/EmSignRootG2CA.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, 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 8319187 + * @bug 8319187 8385585 * @summary Interoperability tests with eMudhra emSign Root CA G2 CS root * @build ValidatePathWithParams * @run main/othervm/manual -Djava.security.debug=certpath EmSignRootG2CA OCSP @@ -74,86 +74,98 @@ public class EmSignRootG2CA { "EJK8NSNmK3FNblQfOyFM7VE0uOGHOUwpMGVM2A==\n" + "-----END CERTIFICATE-----"; - // Owner: CN=test, OU=test, O=test, L=test, ST=test, C=IN - // Issuer: CN=emSign CS CA - G2, O=eMudhra Technologies Limited, OU=emSign PKI, C=IN - // Serial number: 7c9ade672c0ad1b6 - // Valid from: Wed Aug 30 05:39:25 PDT 2023 until: Sat Aug 30 05:39:25 PDT 2025 + // Owner: CN=eMudhra Technologies Limited, O=eMudhra Technologies Limited, + // L=Bangalore, ST=Karnataka, C=IN + // Issuer: CN=emSign CS CA - G2, O=eMudhra Technologies Limited, + // OU=emSign PKI, C=IN + // Serial number: e66c2d81f1cf97f024897e285626ad + // Valid from: Fri Sep 04 00:59:47 PDT 2026 until: Sat Sep 04 00:59:47 + // PDT 2027 private static final String VALID = "-----BEGIN CERTIFICATE-----\n" + - "MIIGNjCCBB6gAwIBAgIIfJreZywK0bYwDQYJKoZIhvcNAQEMBQAwZTELMAkGA1UE\n" + - "BhMCSU4xEzARBgNVBAsTCmVtU2lnbiBQS0kxJTAjBgNVBAoTHGVNdWRocmEgVGVj\n" + - "aG5vbG9naWVzIExpbWl0ZWQxGjAYBgNVBAMTEWVtU2lnbiBDUyBDQSAtIEcyMB4X\n" + - "DTIzMDgzMDEyMzkyNVoXDTI1MDgzMDEyMzkyNVowWDELMAkGA1UEBhMCSU4xDTAL\n" + - "BgNVBAgTBHRlc3QxDTALBgNVBAcTBHRlc3QxDTALBgNVBAoMBHRlc3QxDTALBgNV\n" + - "BAsTBHRlc3QxDTALBgNVBAMTBHRlc3QwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAw\n" + - "ggGKAoIBgQC04pOiSFbl7Bd4wFYXzzyukKh+EmwIq8xRGQDkuYH+C6Zao36VAV+k\n" + - "xGw7lmM3rf4YUcArgZYHfrxgPJNBbGrCi/YnEPYQTNwSrBAePUx1tt13LVBxHfNu\n" + - "cQQT+kqE7064WsYfmfr/uzJZemqVH7lG82DN23+8E/235AIh3lz/pn7T9ByLj7TV\n" + - "zWP40oT0UfQXQvWUpFevPONu/RksRP+NiKV3ji6/wYpvrfodzkrGxw2DPfOh4Iam\n" + - "j6bBH2rkTMToH853plsQGr2ji8OndePfvDdk+5c33Jz1knCNPZSlYQIIp8scyz4z\n" + - "jaUGdoC140FjEA1SMA2WzpRJoE7xjAidLv7jiV596/bTwrIM+IZhzBc8SKRmkdZ6\n" + - "lYjPYJHPqRosRtfxcQne3pY6F4s1aOUtuGJaQS/AJkkykZoOx27plWM5SjtmlrL+\n" + - "7g2/ihWT9CEagYuo44tqk9Tmp3P37+ADAmiXxP0zUxYIv77DSabdArrZ+AB5XUol\n" + - "V8sxE1V6h0UCAwEAAaOCAXUwggFxMB8GA1UdIwQYMBaAFBWGyrZ0lhdIWDSCLM3S\n" + - "4XWer0S3MB0GA1UdDgQWBBQ2k0TE2p46sYwI5M/a1XJ8M5Oc8DAOBgNVHQ8BAf8E\n" + - "BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwNwYDVR0fBDAwLjAsoCqgKIYmaHR0\n" + - "cDovL2NybC5lbXNpZ24uY29tP2VtU2lnbkNTQ0FHMi5jcmwwTgYDVR0gBEcwRTA5\n" + - "BgsrBgEEAYOOIQEAATAqMCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3NpdG9yeS5l\n" + - "bVNpZ24uY29tMAgGBmeBDAEEATBzBggrBgEFBQcBAQRnMGUwIgYIKwYBBQUHMAGG\n" + - "Fmh0dHA6Ly9vY3NwLmVtU2lnbi5jb20wPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBv\n" + - "c2l0b3J5LmVtc2lnbi5jb20vY2VydHMvZW1TaWduQ1NDQUcyLmNydDAMBgNVHRMB\n" + - "Af8EAjAAMA0GCSqGSIb3DQEBDAUAA4ICAQBKLa7j8fNpcnWNv7NegrMKTRy7gycI\n" + - "qrMK848wISX6jl2wg6b275sWQHzQRxA6rbB76bF2HXLFcpITJPaz+vjetYOVQd4v\n" + - "l8iZN52OpN6Pwrheiz7JhdLiHisN+2NKMmF899bH7w1l2Sr/FQl5vqk41gwwWMen\n" + - "99Waf4Bp6p3lvBArK2BbabTs8+16xvmkHEK3d3l3Bu6qTEbQRgUI5XsVXmXXn8Pg\n" + - "IANliTEsbsN9CMWrJ56ciEujU7w2L+IBfvKhl10N1AQNHwpQzwfFyz2BUbACN75o\n" + - "feIUBarM3ssNzpnt7idgkCTwWVrdEL1NHyW967aEMWyVwaRrtkjFOW/0xuSr2rEI\n" + - "jBpPj5RPdP6ZEaqnmg5PIgSrJ8FBjx6JmvVgZH/XEl5MZ7PsvJFfIMun6RxXtGn7\n" + - "QP0+ipkRrI6USNFS84H53Q0WJhQWZUgd3cdm37wpFGvxOVEskIgJNW9SbOgiT9sB\n" + - "zTIy3ceOK2onmUkDM2Q2+Hbc7A4BmNIlW4fpYXvZlM7IXSl9U3Voks92Hi45azgz\n" + - "StWZv9+Ronmmp+b7JKCe7MZXIBHfj0JhAVNJiYTZ9BqkY2VRvuQPVUdKxske9fQ6\n" + - "ciFJ5a6RDOhce6pFloaQu39ci2XCY1N4mIR3vFzpmBNkttlEXviK07XNTv9cnQt6\n" + - "3CW5aMAsfTbmOw==\n" + + "MIIG6zCCBNOgAwIBAgIQAOZsLYHxz5fwJIl+KFYmrTANBgkqhkiG9w0BAQwFADBl\n" + + "MQswCQYDVQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11\n" + + "ZGhyYSBUZWNobm9sb2dpZXMgTGltaXRlZDEaMBgGA1UEAxMRZW1TaWduIENTIENB\n" + + "IC0gRzIwHhcNMjYwOTA0MDc1OTQ3WhcNMjcwOTA0MDc1OTQ3WjCBgzELMAkGA1UE\n" + + "BhMCSU4xEjAQBgNVBAgTCUthcm5hdGFrYTESMBAGA1UEBxMJQmFuZ2Fsb3JlMSUw\n" + + "IwYDVQQKDBxlTXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMSUwIwYDVQQDExxl\n" + + "TXVkaHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMIICIjANBgkqhkiG9w0BAQEFAAOC\n" + + "Ag8AMIICCgKCAgEA5Mh6duhdJ4xfZw3Iwnvy7KIauGVXCpX/EOS3ueDOKPCQ8XG+\n" + + "pWHP+bs1OioHxWwRAo0AVV/hYr9c+nAyAq0Y0RsZGeBDqZUVK0oECYdWvssPP/0o\n" + + "ZUcmiDvDI3NDYKXE8XqPrxd6uHZ0mFkJn+GQHUrTx7gOtNCscijmkeMip9jyLq8B\n" + + "m8c9B6TzkSXD6Q2tB76cRuHGLL7FHDzBut6GZElJicsoeI/AQtLfakz02Taea8Ue\n" + + "ILyLCnpq5jgij2zqk6ozMDd8lpHYvJCwZ7tFHfuxQBcWy9R2qUAeXBUX+Iymq+Me\n" + + "gpv8m3Ov1382p+iP6wpxp/LsDlr+Cg3uil19aFG2GO7WIxiIyDbSY3t6VjhZWFWP\n" + + "YbemMXhiKCMWZmX8bKVb8wJYjxUaBDpCoIq8+gj/XglUjq7vpXN8oARLW69z1fJi\n" + + "Yt0QAlEDLMcM0Rh3wmEr/sqtu7mkBU7Lp1nnqNx4bPXDf69SalbTnM3ukN7QYpgz\n" + + "d/cxzACOQioTwoCDFSHuOBhLuyo81xho9UKzpMR50r7FcePmiLiAtkgl7fZ02U1C\n" + + "DincqL+bLtpUxGcSmxNtI3NF+OqpcG+DUjUFDge7k+WgbFxvzahcxH5i5YdzIRf0\n" + + "y3NbodvHIYmVPcH0vMv1ntywwP1jy9VuAgT24cj+Es5rmPYy8xogrZa95kkCAwEA\n" + + "AaOCAXYwggFyMB8GA1UdIwQYMBaAFBWGyrZ0lhdIWDSCLM3S4XWer0S3MB0GA1Ud\n" + + "DgQWBBQy1M8ziJmPioriHY7mJB7+beUk5zAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0l\n" + + "BAwwCgYIKwYBBQUHAwMwNwYDVR0fBDAwLjAsoCqgKIYmaHR0cDovL2NybC5lbXNp\n" + + "Z24uY29tP2VtU2lnbkNTQ0FHMi5jcmwwTwYDVR0gBEgwRjA6BgwrBgEEAYOOIQEA\n" + + "AQIwKjAoBggrBgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnkuZW1zaWduLmNvbTAI\n" + + "BgZngQwBBAEwcwYIKwYBBQUHAQEEZzBlMCIGCCsGAQUFBzABhhZodHRwOi8vb2Nz\n" + + "cC5lbVNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVwb3NpdG9yeS5lbXNp\n" + + "Z24uY29tL2NlcnRzL2VtU2lnbkNTQ0FHMi5jcnQwDAYDVR0TAQH/BAIwADANBgkq\n" + + "hkiG9w0BAQwFAAOCAgEAL9uz2lWq/Dx1P9jot/DUvDS3u7wKf3qw5XH191kQ1B+S\n" + + "m9/uhkEptH4lanpXoB/QorvTSkSvu2D2LxQOjHbXdYzLJqDO4NNbFw3S7H5jRVWT\n" + + "dRBrb/2VREX5LJ2NBVgxETCpOMyXKgpmefcvVYxZ1jKa80H6Jqd7YzPpFhwsHglX\n" + + "/YQX+jYUWjdxkWSo48jlAbi81vUj5snn+AbrFnq8RRy1r22Z5k3zSFNGz2W9iWzS\n" + + "UjpSQoaz7e4/L+2flScEydmmv1F2MH9boP5XIZmNXKp6sTr55jZQmQiWysiERPJ2\n" + + "0bHhM9Q8qr+Sp8NWVZs5tIYnWJSyBasOctkVvl2ADdrIofR9cmWaP1/EdB5Hl1cx\n" + + "Aqo3FKfXK5ZNRHt7B7v11PoBiwzYqk45L03AABNmuZcNC3HkG5emfBrlY0Ud6QuK\n" + + "/8Oi4+G01H/6DFCqMqEFR/AFQtzPDnlaEL3XvoZyJcIJARP14XTyXXlUJt5fI0yq\n" + + "E6F0KsJCeCRcGKZcjLMWyN+5mPsNdT9EdQOpYJ8dXLtB5r2uN0xsjcOPpFTAIwRt\n" + + "fUW5MUFiZZvWqqadhI1EhKhWDTyTn8vJGWNiqXKbbfedck/k/B5Kc75A5nfuBB/u\n" + + "awVsnhMuAU7yVUOH37dGv4b4tKRnkW/L+owhEOfbWbiRrtmQ4z/u5+84yxddNiY=\n" + "-----END CERTIFICATE-----"; - // Owner: CN=test, OU=test, O=test, L=test, ST=test, C=IN - // Issuer: CN=emSign CS CA - G2, O=eMudhra Technologies Limited, OU=emSign PKI, C=IN - // Serial number: cf02dedd03d2f509 - // Valid from: Thu Oct 05 22:38:51 PDT 2023 until: Sun Oct 05 22:38:51 PDT 2025 + // Owner: CN=eMudhra Technologies Limited, O=eMudhra Technologies Limited, + // L=Bangalore, ST=Karnataka, C=IN + // Issuer: CN=emSign CS CA - G2, O=eMudhra Technologies Limited, + // OU=emSign PKI, C=IN + // Serial number: 399515f0e9db1ec53b695df8a4216 + // Valid from: Sat Sep 05 10:12:31 PDT 2026 until: Sun Sep 05 10:12:31 + // PDT 2027 private static final String REVOKED = "-----BEGIN CERTIFICATE-----\n" + - "MIIGNzCCBB+gAwIBAgIJAM8C3t0D0vUJMA0GCSqGSIb3DQEBDAUAMGUxCzAJBgNV\n" + - "BAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRl\n" + - "Y2hub2xvZ2llcyBMaW1pdGVkMRowGAYDVQQDExFlbVNpZ24gQ1MgQ0EgLSBHMjAe\n" + - "Fw0yMzEwMDYwNTM4NTFaFw0yNTEwMDYwNTM4NTFaMFgxCzAJBgNVBAYTAklOMQ0w\n" + - "CwYDVQQIEwR0ZXN0MQ0wCwYDVQQHEwR0ZXN0MQ0wCwYDVQQKDAR0ZXN0MQ0wCwYD\n" + - "VQQLEwR0ZXN0MQ0wCwYDVQQDEwR0ZXN0MIIBojANBgkqhkiG9w0BAQEFAAOCAY8A\n" + - "MIIBigKCAYEAmUSghjvjUvVgYguH2PMLwW4TwtYsNDpAuGPqux53lI9v9S5u4oAv\n" + - "m1Sa3MW7CeEnhHNAIFu/AKvNXSfkvnJpTozWstZMjd93DcNacteBG0fBKTkIq+5k\n" + - "A8qIBiXWk8NORlbjV5bXnoW2pO7wbrALDK3FGf2JAQjuYWXE1mlVk0+SJewUSN+F\n" + - "XTl63V3tcaqjxhoViY8/dCWc7pNTPgQ/f+Rmnm1bpE0hxVPpQ29+60lyoNtKiOWj\n" + - "InKRKBV8jYkR/xI13bKWguaxZnswpf2MrophQTvO9ivPHADWhZlNYYjYYEMl4tbi\n" + - "rG2EquJ7g8Jdo+aL3BggLv5gFkpfoEcaveNuUWy7ggUl7MNhvgDdWdoi6VY7R8Fi\n" + - "F52+JqPByGpHkZKi0wPa3BaI7guGGyCn3TMe66kNTMS4ADxHktqQlpNSaYYl/84G\n" + - "lnr2WxQt/W+sXoorlKc/Kh0ubbm6eDzPE8kkIDV2uIxUEgSL7SJQ95yf5XgRihoH\n" + - "KoBA45iR5vCtAgMBAAGjggF1MIIBcTAfBgNVHSMEGDAWgBQVhsq2dJYXSFg0gizN\n" + - "0uF1nq9EtzAdBgNVHQ4EFgQUDs5dk74eElzdEKdxIlkzISoWSFkwDgYDVR0PAQH/\n" + - "BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDcGA1UdHwQwMC4wLKAqoCiGJmh0\n" + - "dHA6Ly9jcmwuZW1zaWduLmNvbT9lbVNpZ25DU0NBRzIuY3JsME4GA1UdIARHMEUw\n" + - "OQYLKwYBBAGDjiEBAAEwKjAoBggrBgEFBQcCARYcaHR0cDovL3JlcG9zaXRvcnku\n" + - "ZW1TaWduLmNvbTAIBgZngQwBBAEwcwYIKwYBBQUHAQEEZzBlMCIGCCsGAQUFBzAB\n" + - "hhZodHRwOi8vb2NzcC5lbVNpZ24uY29tMD8GCCsGAQUFBzAChjNodHRwOi8vcmVw\n" + - "b3NpdG9yeS5lbXNpZ24uY29tL2NlcnRzL2VtU2lnbkNTQ0FHMi5jcnQwDAYDVR0T\n" + - "AQH/BAIwADANBgkqhkiG9w0BAQwFAAOCAgEAGa2XSoRkoIkHHHGXrdzTBCf/+KgK\n" + - "FlHhqlBOk5rwLDX1sfNlmsaz10I69phE90Ac8Coa/xCrBaFrTYqRvmkY9gU19jkn\n" + - "FdVcwQEHNku7Ro/Z/mbyi+aTBzHMTy0Vl4HqVnQInjV891n64SerUuAB7wNVOOho\n" + - "GoBfpf6lzDzzuEmetFokHYv1tWGQqPF/dHLARQraUlQpWjsnOx0QcZ5cM79REONE\n" + - "y6uzXT2vaatT3ns8Mtx8zooq+t8pnZlXJqlrwNTcnPad9gSsVu6vfsnWhLhz0VLG\n" + - "sYPXcWIssLbBQW3v5z0l1Isj7vy2UFfbn8AmZ0PanPo3v3C2sk19DK+Zlc9xBAXc\n" + - "KKwc4m8le6QkP/EB2wUA7ey5Cf29hjNDJpZznquEaWl9aKbBRdJDKsK88IBJjzK0\n" + - "Gbpw9fYJ3txuGA7Q27gyaZAeGAIrFvOtRY0XFbr20qSh2GBBYN57+lBPh4UKqgy8\n" + - "Z2Kk/2jK9k+nm41JYCmwVZHg3Va9RRfW8FkeE95gAUFPDWjeV+GvcimCbcB3DwaZ\n" + - "9fy1qfV4xsduhC3ei6f7Ask8LbAEWaEIXmgK10YbIfhzomCyCzlA+E+gwkq/bmkv\n" + - "B8hh27KWA6IRt7URI51MZlh0e8fULyXlOZcoJA/IPX9RdePa2RHFuPSypBHjoN7z\n" + - "6bCML1XZ2xnHIAg=\n" + + "MIIG6jCCBNKgAwIBAgIPA5lRXw6dsexTtpXfikIWMA0GCSqGSIb3DQEBDAUAMGUx\n" + + "CzAJBgNVBAYTAklOMRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVk\n" + + "aHJhIFRlY2hub2xvZ2llcyBMaW1pdGVkMRowGAYDVQQDExFlbVNpZ24gQ1MgQ0Eg\n" + + "LSBHMjAeFw0yNjA5MDUxNzEyMzFaFw0yNzA5MDUxNzEyMzFaMIGDMQswCQYDVQQG\n" + + "EwJJTjESMBAGA1UECBMJS2FybmF0YWthMRIwEAYDVQQHEwlCYW5nYWxvcmUxJTAj\n" + + "BgNVBAoMHGVNdWRocmEgVGVjaG5vbG9naWVzIExpbWl0ZWQxJTAjBgNVBAMTHGVN\n" + + "dWRocmEgVGVjaG5vbG9naWVzIExpbWl0ZWQwggIiMA0GCSqGSIb3DQEBAQUAA4IC\n" + + "DwAwggIKAoICAQDamKtV3CD/F8V6OpeyMvQZakL/CLsYZVSlSHN34u2nxtpG5RIt\n" + + "buEMQfZl1lsLQlV39TgoCfrf7kY2S9xLZcMapUGMwT0HoP+rRnyVJpfhgq/ULlX/\n" + + "L2KgGxJyUP6XpVcdrlyrHOAvErFhdhdg9L4/tTwOoarHUZCNBB1Wx3Rl1sgCMVbl\n" + + "UcbzgJZulYhMJ+deEnHwJTPLO/GTFHek7hGy7bYoD2jhwUgG6Yjae5rZWHnLaKRg\n" + + "zACpgQl2sUAtJ7l8Zh0Ig14BTzM0OTfQutPaB3JYr81wZj4awhk39MDf4ob6kcEm\n" + + "8KqqYqlARhhFe8XOCZ5IrmQEzie2am0EZICk6g2nBvIcMUgPN9yFOGQdUaSSQe5+\n" + + "lA6skGA/ZADVCBf9E1j/tqABdcFdYiPvpInlRxXCK/xxbspupQhffyamqUtj7PT+\n" + + "tIdAaruiFV/PIx6MvmNpBhzyPt01QJlAy5GU//5/EnQ7HW/np9jjHr0QdZFbnis+\n" + + "O+VloqNSP7UW9eWo1mMwQWLGr/PQHNERGGsPb6gofxUJdKgp4kbg9rqfBkLdYLBV\n" + + "jVYAKIpOlP7b93eta5qr0DOImBLor5fvZOs7bljltp68S1mmVxMsvezmSJIcvLvG\n" + + "R0G4YWDvobhcCVmEk1nV580+/3OZEMbBk3R4oOB2MUv4eiCYrlpWI0xmjQIDAQAB\n" + + "o4IBdjCCAXIwHwYDVR0jBBgwFoAUFYbKtnSWF0hYNIIszdLhdZ6vRLcwHQYDVR0O\n" + + "BBYEFMQn0uMfp84zx4vz2EYeBnzyyh9fMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUE\n" + + "DDAKBggrBgEFBQcDAzA3BgNVHR8EMDAuMCygKqAohiZodHRwOi8vY3JsLmVtc2ln\n" + + "bi5jb20/ZW1TaWduQ1NDQUcyLmNybDBPBgNVHSAESDBGMDoGDCsGAQQBg44hAQAB\n" + + "AjAqMCgGCCsGAQUFBwIBFhxodHRwOi8vcmVwb3NpdG9yeS5lbXNpZ24uY29tMAgG\n" + + "BmeBDAEEATBzBggrBgEFBQcBAQRnMGUwIgYIKwYBBQUHMAGGFmh0dHA6Ly9vY3Nw\n" + + "LmVtU2lnbi5jb20wPwYIKwYBBQUHMAKGM2h0dHA6Ly9yZXBvc2l0b3J5LmVtc2ln\n" + + "bi5jb20vY2VydHMvZW1TaWduQ1NDQUcyLmNydDAMBgNVHRMBAf8EAjAAMA0GCSqG\n" + + "SIb3DQEBDAUAA4ICAQBy0UYUXy/AwPgRmUWu1B0xeq9hU2vFwoFmGbOkd2sJqOOi\n" + + "KdIbpjvIdLtPchIasENu+oc55ENgmbD4u5WDxGspBjL18sbE6jmzmGY1dsbCgF17\n" + + "Pi9KvlX3LRtD8qTD2oJ5y/YJ7fMKW4j+h4ssNrmA2NboXhgX3e+idQeZ2ItAgV0k\n" + + "s3STGRkoOKdsuwpeD/+69nXVIIYusVSgOuYXZb/ViWcL3cMq75cZdR/WYixxU9ZV\n" + + "Z55NQKikOGVTuKBpDv9BEa5yqAK32RcajUl7R7bT7AuY+LnTRHtX0P4sCkohj1kP\n" + + "9JGoFWN1NIJeCou5GSRmuWLYpnMfi9oDvMPt2e7GUqKkNF+OXTxWfq5A0xtkLWGN\n" + + "3qEr9xD34ZnFP5h0c6sE8hzee65erhqSo6LqlQMGINP2gL+fUG+smdX0JQYbX9hP\n" + + "raKmp53+aHwolzn0R3t9otgZ6yVdAZLScNLXqDd55/gr/TDrfu4XzRTHK9RCrMzT\n" + + "trvbKKtqTuwEp1vQBoced60CI1ZjG41tipF1irhU+pyHk/Kt9YiExp6QZGoBznTY\n" + + "9Rvw5No0XoVQHLC56JbsGUot8bVVpGNXzF8PtWBmskqttsw1XTgSUOsnoopfb+Eb\n" + + "fpPUdqTDs47FRowITPbj4cgYzYRKWEc7xh8fozZ18lN8yAP6hA2OfDN3j4HrCA==\n" + "-----END CERTIFICATE-----"; public static void main(String[] args) throws Exception { @@ -174,6 +186,6 @@ public static void main(String[] args) throws Exception { // Validate Revoked pathValidator.validate(new String[]{REVOKED, INT}, ValidatePathWithParams.Status.REVOKED, - "Thu Oct 05 22:51:36 PDT 2023", System.out); + "Sat Sep 05 10:32:30 PDT 2026", System.out); } } diff --git a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java index bb9df70baf94..17d098006d93 100644 --- a/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java +++ b/test/jdk/sun/security/lib/cacerts/VerifyCACerts.java @@ -29,7 +29,7 @@ * 8243559 8225072 8258630 8259312 8256421 8225081 8225082 8225083 8245654 * 8305975 8304760 8307134 8295894 8314960 8317373 8317374 8318759 8319187 * 8321408 8316138 8341057 8303770 8350498 8359170 8361212 8372351 8387123 - * 8386371 + * 8386371 8392771 * @summary Check root CA entries in cacerts file */ import java.io.ByteArrayInputStream; @@ -49,13 +49,13 @@ public class VerifyCACerts { // The numbers of certs now. // SapMachine 2021-09-23: Additional certificate for SAP - private static final int COUNT = 110; + private static final int COUNT = 112; // SHA-256 of cacerts, can be generated with // shasum -a 256 cacerts | sed -e 's/../&:/g' | tr '[:lower:]' '[:upper:]' | cut -c1-95 // SapMachine 2021-09-23: Additional certificate for SAP private static final String CHECKSUM - = "84:57:41:B9:A2:63:08:48:F1:FA:2E:F4:EC:AD:9B:88:E9:F9:43:CC:BF:70:09:96:4D:07:BB:A2:79:40:6C:0F"; + = "E3:3C:F7:4C:16:02:30:58:29:57:83:B3:04:89:47:B6:4D:BA:F4:6E:E4:14:98:C4:58:6D:8F:55:27:F9:6A:A2"; // Hex formatter to upper case with ":" delimiter private static final HexFormat HEX = HexFormat.ofDelimiter(":").withUpperCase(); @@ -285,6 +285,10 @@ public class VerifyCACerts { "6B:9C:08:E8:6E:B0:F7:67:CF:AD:65:CD:98:B6:21:49:E5:49:4A:67:F5:84:5E:7B:D1:ED:01:9F:27:B8:6B:D6"); put("wisekeyglobalrootgcca [jdk]", "85:60:F9:1C:36:24:DA:BA:95:70:B5:FE:A0:DB:E3:6F:F1:1A:83:23:BE:94:86:85:4F:B3:F3:4A:55:71:19:8D"); + put("certumtrustedrootca [jdk]", + "FE:76:96:57:38:55:77:3E:37:A9:5E:7A:D4:D9:CC:96:C3:01:57:C1:5D:31:76:5B:A9:B1:57:04:E1:AE:78:FD"); + put("certumec384ca [jdk]", + "6B:32:80:85:62:53:18:AA:50:D1:73:C9:8D:8B:DA:09:D5:7E:27:41:3D:11:4C:F7:87:A0:F5:D0:6C:03:0C:F6"); } }; diff --git a/test/jdk/valhalla/valuetypes/NullRestrictedTest.java b/test/jdk/valhalla/valuetypes/NullRestrictedTest.java index 1bea720ca06a..43ad325d19d4 100644 --- a/test/jdk/valhalla/valuetypes/NullRestrictedTest.java +++ b/test/jdk/valhalla/valuetypes/NullRestrictedTest.java @@ -27,6 +27,7 @@ * @summary Test reflection and method handle on accessing a field of a null-restricted value class * that may be flattened or non-flattened * @enablePreview + * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true") * @run junit/othervm NullRestrictedTest * @run junit/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseFieldFlattening NullRestrictedTest */ diff --git a/test/jdk/valhalla/valuetypes/Reflection.java b/test/jdk/valhalla/valuetypes/Reflection.java index bcf68372ed85..f0fb5c20da35 100644 --- a/test/jdk/valhalla/valuetypes/Reflection.java +++ b/test/jdk/valhalla/valuetypes/Reflection.java @@ -26,6 +26,7 @@ * @test * @summary test core reflection on value classes * @enablePreview + * @requires (vm.opt.PreloadClasses == null | vm.opt.PreloadClasses == "true") * @run junit/othervm Reflection */ diff --git a/test/jdk/valhalla/valuetypes/ValueClassPreviewTest.java b/test/jdk/valhalla/valuetypes/ValueClassPreviewTest.java index 377d61071bdc..ed259be03d9d 100644 --- a/test/jdk/valhalla/valuetypes/ValueClassPreviewTest.java +++ b/test/jdk/valhalla/valuetypes/ValueClassPreviewTest.java @@ -27,6 +27,7 @@ * @modules java.base/jdk.internal.value * @library /test/lib * @enablePreview + * @requires (vm.opt.UseFieldFlattening == null | vm.opt.UseFieldFlattening == "true") * @compile ${test.file} * @run driver jdk.test.lib.helpers.StrictProcessor * ValueClassPreviewTest$StrictStuff diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 9ef2b22b5a84..1e5af7eb383b 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -122,6 +122,7 @@ public Map call() { map.put("vm.cds.default.archive.available", this::vmCDSDefaultArchiveAvailable); map.put("vm.cds.nocoops.archive.available", this::vmCDSNocoopsArchiveAvailable); map.put("vm.cds.nocoh.archive.available", this::vmCDSNocohArchiveAvailable); + map.put("vm.cds.nocoops.nocoh.archive.available", this::vmCDSNocoopsNocohArchiveAvailable); map.put("vm.cds.custom.loaders", this::vmCDSForCustomLoaders); map.put("vm.cds.supports.aot.class.linking", this::vmCDSSupportsAOTClassLinking); map.put("vm.cds.supports.aot.code.caching", this::vmCDSSupportsAOTCodeCaching); @@ -399,29 +400,39 @@ protected String vmHasDTrace() { return "" + WB.isDTraceIncluded(); } - /** - * Check for CDS support. - * - * @return true if CDS is supported by the VM to be tested. - */ - protected String vmCDS() { + // Check if the VM supports CDS. + private boolean isCDSSupported(){ boolean noJvmtiAdded = allFlags() .filter(s -> s.startsWith("-agentpath")) .findAny() .isEmpty(); - return "" + (noJvmtiAdded && WB.isCDSIncluded()); + return noJvmtiAdded && WB.isCDSIncluded(); + } + + /** + * Check for CDS support. + * + * @return "true" if CDS is supported by the VM to be tested. + */ + protected String vmCDS() { + return "" + isCDSSupported(); } - // Returns a platform-aware path for the specified archive file. - private Path archivePath(String archiveName) { + // Returns a platform-aware path for the specified archive file suffix. + private Path archivePath(String archiveSuffix) { String archiveSubdir = (Platform.isWindows() ? "bin" : "lib"); + String archiveName = "classes" + archiveSuffix; + if (PreviewFeatures.isEnabled()) { + archiveName += "_preview"; + } + archiveName += ".jsa"; return Paths.get(System.getProperty("java.home"), archiveSubdir, "server", archiveName); } // Returns true if a CDS archive file with specified name exists. - private boolean archivePathExists(String archiveName) { - return Files.exists(archivePath(archiveName)); + private boolean archivePathExists(String archiveSuffix) { + return Files.exists(archivePath(archiveSuffix)); } /** @@ -430,7 +441,7 @@ private boolean archivePathExists(String archiveName) { * @return true if CDS default archive classes.jsa exists in the JDK to be tested. */ protected String vmCDSDefaultArchiveAvailable() { - return "" + ("true".equals(vmCDS()) && archivePathExists("classes.jsa")); + return "" + (isCDSSupported() && archivePathExists("")); } /** @@ -439,7 +450,7 @@ protected String vmCDSDefaultArchiveAvailable() { * @return true if CDS archive classes_nocoops.jsa exists in the JDK to be tested. */ protected String vmCDSNocoopsArchiveAvailable() { - return "" + ("true".equals(vmCDS()) && archivePathExists("classes_nocoops.jsa")); + return "" + (isCDSSupported() && archivePathExists("_nocoops")); } /** @@ -448,7 +459,16 @@ protected String vmCDSNocoopsArchiveAvailable() { * @return true if CDS archive classes_nocoh.jsa exists in the JDK to be tested. */ protected String vmCDSNocohArchiveAvailable() { - return "" + ("true".equals(vmCDS()) && archivePathExists("classes_nocoh.jsa")); + return "" + (isCDSSupported() && archivePathExists("_nocoh")); + } + + /** + * Check for existence of CDS archive with no compressed oops and no compact object headers enabled. + * + * @return true if CDS archive classes_nocoops_nocoh.jsa exists in the JDK to be tested. + */ + protected String vmCDSNocoopsNocohArchiveAvailable() { + return "" + (isCDSSupported() && archivePathExists("_nocoops_nocoh")); } /** @@ -457,7 +477,7 @@ protected String vmCDSNocohArchiveAvailable() { * @return true if CDS provides support for customer loader in the VM to be tested. */ protected String vmCDSForCustomLoaders() { - return "" + ("true".equals(vmCDS()) && Platform.areCustomLoadersSupportedForCDS()); + return "" + (isCDSSupported() && Platform.areCustomLoadersSupportedForCDS()); } /** @@ -465,7 +485,7 @@ protected String vmCDSForCustomLoaders() { * with the current set of jtreg VM options. */ protected String vmCDSCanWriteArchivedJavaHeap() { - return "" + ("true".equals(vmCDS()) && WB.canWriteJavaHeapArchive()); + return "" + (isCDSSupported() && WB.canWriteJavaHeapArchive()); } /** @@ -473,7 +493,7 @@ protected String vmCDSCanWriteArchivedJavaHeap() { * with the current set of jtreg VM options. */ protected String vmCDSCanWriteMappedArchivedJavaHeap() { - return "" + ("true".equals(vmCDS()) && WB.canWriteMappedJavaHeapArchive()); + return "" + (isCDSSupported() && WB.canWriteMappedJavaHeapArchive()); } /** @@ -481,7 +501,7 @@ protected String vmCDSCanWriteMappedArchivedJavaHeap() { * with the current set of jtreg VM options. */ protected String vmCDSCanWriteStreamedArchivedJavaHeap() { - return "" + ("true".equals(vmCDS()) && WB.canWriteStreamedJavaHeapArchive()); + return "" + (isCDSSupported() && WB.canWriteStreamedJavaHeapArchive()); } /** @@ -497,6 +517,7 @@ protected String vmCDSSupportsAOTClassLinking() { */ protected String vmCDSSupportsAOTCodeCaching() { if ("true".equals(vmCDSSupportsAOTClassLinking()) && + !"true".equals(isPreviewEnabled()) && !"zero".equals(vmFlavor()) && (Platform.isX64() || Platform.isAArch64() || Platform.isRISCV64())) { return "true"; diff --git a/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java b/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java index dac53424ab42..98d901594377 100644 --- a/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java +++ b/test/langtools/jdk/javadoc/doclet/testNavigation/TestModuleNavigation.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8196027 8196202 8320458 8342705 8371021 + * @bug 8196027 8196202 8320458 8342705 8371021 8377548 * @summary test navigation links * @modules jdk.compiler/com.sun.tools.javac.api * jdk.compiler/com.sun.tools.javac.main @@ -86,7 +86,7 @@ public void testSingleModule(Path base) throws Exception {

  • Index
  • Search
  • Help
  • -
  • + """, """