Compare commits

...

88 Commits

Author SHA1 Message Date
Jesper Wilhelmsson
6705a9255d 8345276: Remove EA from the JDK 24 version string with first RC promotion
Reviewed-by: darcy, mikael, erikj
2025-02-06 00:16:21 +00:00
Mark Powers
681c6d4339 8349084: Update vectors used in several PQC benchmarks
Reviewed-by: weijun
Backport-of: 2f2f7cf0dd
2025-02-05 23:26:25 +00:00
Jaikiran Pai
f0837b2183 8349183: [BACKOUT] Optimization for StringBuilder append boolean & null
8349239: [BACKOUT] Reuse StringLatin1::putCharsAt and StringUTF16::putCharsAt

Reviewed-by: rriggs, liach
Backport-of: 618c5eb27b
2025-02-05 06:51:01 +00:00
Martin Doerr
b1659e345a 8348562: ZGC: segmentation fault due to missing node type check in barrier elision analysis
Reviewed-by: kvn, thartmann
Backport-of: afcc2b03af
2025-02-04 13:10:49 +00:00
Daniel Lundén
47c15b5ff8 8348658: [AArch64] The node limit in compiler/codegen/TestMatcherClone.java is too strict
Reviewed-by: shade, epeter
Backport-of: ee87d187d1
2025-02-03 18:21:52 +00:00
Ioi Lam
5f5ed961db 8348890: Fix docs for -XX:AOT* options in java man page
Reviewed-by: kvn, jrose
Backport-of: cdc84acdcc
2025-02-01 00:32:32 +00:00
Ioi Lam
df57c97d29 8348515: Add docs for -XX:AOT* options in java man pages
Reviewed-by: kvn
Backport-of: 46f48e4e3d
2025-01-31 23:13:11 +00:00
Ioi Lam
2a1a416c37 8349122: -XX:+AOTClassLinking is not compatible with jdwp
Reviewed-by: jrose, kvn
Backport-of: 03f5c33b53
2025-01-31 23:11:03 +00:00
Ioi Lam
89c46f11f8 8349009: JVM fails to start when AOTClassLinking is used with unverifiable old classes
Reviewed-by: kvn, shade, jrose
Backport-of: 1ac2d6e0fb
2025-01-31 23:08:40 +00:00
Ioi Lam
b1b55f712c 8348752: Enable -XX:+AOTClassLinking by default when -XX:AOTMode is specified
Reviewed-by: lfoltan, shade, kvn
Backport-of: d266ca965d
2025-01-31 23:05:39 +00:00
Rajan Halade
15f90f0c7b 8349017: Update ML tests to verify against ACVP 1.1.0.38 version
Reviewed-by: weijun
Backport-of: 13d852a0b8
2025-01-31 17:49:28 +00:00
Eric Caspole
926455d6c5 8345405: Add JMH showing the regression in 8341649
Reviewed-by: coleenp
Backport-of: 35c00532a1
2025-01-31 15:06:34 +00:00
Nizar Benalla
ec00b6b7ac 8348975: Broken links in the JDK 24 JavaDoc API documentation, build 33
Reviewed-by: liach
Backport-of: 22069ff42b
2025-01-31 01:14:40 +00:00
Tobias Hartmann
2d4731917d 8348631: Crash in PredictedCallGenerator::generate after JDK-8347006
Reviewed-by: chagedorn
Backport-of: 55c3e78f4e
2025-01-29 07:33:41 +00:00
Chen Liang
612ae737c0 8342465: Improve API documentation for java.lang.classfile
Reviewed-by: asotona
Backport-of: 1d8ccb8920
2025-01-27 23:31:47 +00:00
Justin Lu
a315b9326b 8347498: JDK 24 RDP2 L10n resource files update
Reviewed-by: dnguyen, naoto, iris
Backport-of: dec93675ab
2025-01-27 17:24:45 +00:00
Mikael Vidstedt
ab43ba0ef8 8348327: Incorrect march flag when building libsleef/vector_math_neon.c
Reviewed-by: erikj, shade
Backport-of: 3ebf88996f
2025-01-24 18:07:26 +00:00
Chen Liang
564e0a2076 8342466: Improve API documentation for java.lang.classfile.attribute
8347762: ClassFile attribute specification refers to non-SE modules

Reviewed-by: asotona
Backport-of: 973c630777
2025-01-24 14:56:35 +00:00
Richard Reingruber
53aa9f2596 8347817: Timeouts running test/jdk/java/lang/String/concat/HiddenClassUnloading.java with fastdebug builds
Reviewed-by: mdoerr
Backport-of: 15d6469e8d
2025-01-23 08:28:58 +00:00
Calvin Cheung
99e21c6aaf 8348013: [doc] fix typo in java.md caused by JDK-8347763
Reviewed-by: iklam
Backport-of: e1cf3517ae
2025-01-22 18:47:06 +00:00
Jaikiran Pai
4ce95c95ef Merge
Reviewed-by: dfuchs
2025-01-22 11:28:52 +00:00
Christian Hagedorn
93ea8e708d 8330045: Enhance array handling
Co-authored-by: Christian Hagedorn <chagedorn@openjdk.org>
Co-authored-by: Emanuel Peter <epeter@openjdk.org>
Co-authored-by: Francisco Ferrari Bihurriet <fferrari@redhat.com>
Co-authored-by: Martin Balao <mbalao@redhat.com>
Reviewed-by: rhalade, ahgross, thartmann, epeter, adinn, roland
2025-01-22 14:56:30 +05:30
Roger Riggs
a9fae67913 8339180: Enhanced Building of Processes: Follow-on Issue
Reviewed-by: naoto, djelinski
2025-01-22 14:56:30 +05:30
Jayathirth D V
aaf3415de8 8336564: Enhance mask blit functionality redux
Reviewed-by: rhalade, mschoene, psadhukhan, prr
2025-01-22 14:56:30 +05:30
Roger Riggs
535922059c 8335428: Enhanced Building of Processes
Reviewed-by: rhalade, djelinski
2025-01-22 14:56:30 +05:30
Calvin Cheung
bc19494216 8347763: [doc] Add documentation of module options for JEP 483
Reviewed-by: iklam
Backport-of: 17e3df652f
2025-01-22 05:52:55 +00:00
William Kemper
febcfd69ff 8345750: Shenandoah: Test TestJcmdHeapDump.java#aggressive intermittent assert(gc_cause() == GCCause::_no_gc) failed: Over-writing cause
Reviewed-by: ysr
Backport-of: 6a29a8110e
2025-01-21 23:10:22 +00:00
Markus Grönlund
1495f7addb 8345493: JFR: JVM.flush hangs intermittently
Reviewed-by: egahlin
Backport-of: 4257215a9f
2025-01-15 16:42:31 +00:00
Weijun Wang
c141aa1e08 8347596: Update HSS/LMS public key encoding
Reviewed-by: mullan
Backport-of: 0ee6ba9c4c
2025-01-15 14:26:23 +00:00
Coleen Phillimore
467f407037 8344068: Windows x86-64: Out of CodeBuffer space when generating final stubs
Reviewed-by: kvn, jwaters
Backport-of: 830173fcb0
2025-01-15 12:37:08 +00:00
Qizheng Xing
f7858e2422 8346831: Remove the extra closing parenthesis in CTW Makefile
Reviewed-by: thartmann, chagedorn
Backport-of: 79958470e0
2025-01-15 08:21:47 +00:00
Jan Lahoda
6965840e0d 8347646: module-info classfile missing the preview flag
Reviewed-by: asotona
Backport-of: bb93f67ea8
2025-01-15 05:14:53 +00:00
Erik Gahlin
1399f253b0 8343510: JFR: Remove AccessControlContext from FlightRecorder::addListener specification
Reviewed-by: mgronlun
Backport-of: 1bf2f5c8a9
2025-01-14 22:31:31 +00:00
Joe Darcy
f45a23cabd 8347605: Use spec tag to refer to IEEE 754 standard
Reviewed-by: liach, bpb, iris
Backport-of: 7c883c284d
2025-01-14 16:39:26 +00:00
Christian Hagedorn
f42e2c10c6 8347554: [BACKOUT] C2: implement optimization for series of Add of unique value
Reviewed-by: kvn, thartmann
Backport-of: 062f2dcfe5
2025-01-14 15:20:53 +00:00
Weijun Wang
57c46ac2fe 8342062: Reformat keytool and jarsigner output for keys with a named parameter set
Reviewed-by: mullan
Backport-of: fa5ff82eb3
2025-01-14 14:06:36 +00:00
Viktor Klang
24053d9b6a 8347274: Gatherers.mapConcurrent exhibits undesired behavior under variable delays, interruption, and finishing
Reviewed-by: alanb
Backport-of: 450636ae28
2025-01-14 13:31:29 +00:00
Damon Fenacci
e76cc44502 8347407: [BACKOUT] C1/C2 don't handle allocation failure properly during initialization (RuntimeStub::new_runtime_stub fatal crash)
Reviewed-by: thartmann, kvn
Backport-of: b37f123625
2025-01-14 07:35:21 +00:00
Chen Liang
4a623a2b6d 8342468: Improve API documentation for java.lang.classfile.constantpool
8347163: Javadoc error in ConstantPoolBuilder after JDK-8342468

Reviewed-by: asotona
Backport-of: bcefab5e55
2025-01-13 17:00:54 +00:00
Abhishek Kumar
ecdc322029 8339728: [Accessibility,Windows,JAWS] Bug in the getKeyChar method of the AccessBridge class
Reviewed-by: aivanov, kizune
Backport-of: a46ae7031e
2025-01-13 16:37:38 +00:00
Tobias Hartmann
da74fbd920 8347006: LoadRangeNode floats above array guard in arraycopy intrinsic
Reviewed-by: chagedorn
Backport-of: 82e2a79122
2025-01-13 13:45:19 +00:00
Patricio Chilano Mateo
f0a89c5d8e 8310340: assert(_thread->is_interp_only_mode() || stub_caller) failed: expected a stub-caller
Reviewed-by: sspitsyn
Backport-of: ea49537726
2025-01-10 15:27:09 +00:00
Erik Gahlin
c61fbfd6ea 8345337: JFR: jfr view should display all direct subfields for an event type
Reviewed-by: mgronlun
Backport-of: 672c413c61
2025-01-10 13:51:45 +00:00
Fei Yang
92a4e23467 8346838: RISC-V: runtime/CommandLine/OptionsValidation/TestOptionsWithRanges.java crash with debug VMs
Reviewed-by: rehn
Backport-of: 379ac349d1
2025-01-10 10:45:42 +00:00
Fredrik Bredberg
ba36d309c3 8332506: SIGFPE In ObjectSynchronizer::is_async_deflation_needed()
Reviewed-by: coleenp
Backport-of: cbabc04515
2025-01-10 08:56:45 +00:00
Aleksey Shipilev
41630c5c32 8347127: CTW fails to build after JDK-8334733
Reviewed-by: phh
Backport-of: e413fc643c
2025-01-10 08:43:03 +00:00
Weijun Wang
864d0fde23 8347289: HKDF delayed provider selection failed with non-extractable PRK
Reviewed-by: valeriep
Backport-of: db7fa6a2c6
2025-01-09 20:44:54 +00:00
William Kemper
ff9b8e4607 8346737: GenShen: Generational memory pools should not report zero for maximum capacity
Reviewed-by: kdnilsen, ysr
Backport-of: 249f141211
2025-01-09 17:07:14 +00:00
Severin Gehwolf
7d4fa7818b 8345259: Disallow ALL-MODULE-PATH without explicit --module-path
Reviewed-by: alanb, mchung
Backport-of: bcb1bdaae7
2025-01-09 10:04:19 +00:00
Severin Gehwolf
c033806b8c 8346739: jpackage tests failed after JDK-8345259
Reviewed-by: shade, mchung, asemenyuk
Backport-of: 7ba969a576
2025-01-09 10:03:54 +00:00
Alexey Semenyuk
bf45128055 8346872: tools/jpackage/windows/WinLongPathTest.java fails
Reviewed-by: almatvee
Backport-of: 4d18e5a1e2
2025-01-09 03:45:05 +00:00
Calvin Cheung
29c6bf23fb 8346457: AOT cache creation crashes with "assert(pair_at(i).match() < pair_at(i+1).match()) failed: unsorted table entries"
Reviewed-by: iklam
Backport-of: 8d388ccd9e
2025-01-08 23:30:52 +00:00
SendaoYan
c3b52089f6 8346965: Multiple compiler/ciReplay test fails with -XX:+SegmentedCodeCache
Reviewed-by: epeter
Backport-of: cf3e48e771
2025-01-08 15:24:09 +00:00
Per Minborg
860b30ddf9 8347047: Cleanup action passed to MemorySegment::reinterpret keeps old segment alive
Reviewed-by: shade
Backport-of: b0c935c03e
2025-01-08 10:16:28 +00:00
Tobias Hartmann
256856a5a1 8343747: C2: TestReplicateAtConv.java crashes with -XX:MaxVectorSize=8
Reviewed-by: chagedorn
Backport-of: 874d68a96c
2025-01-07 09:49:56 +00:00
William Kemper
cc7c293bce 8345970: pthread_getcpuclockid related crashes in shenandoah tests
Reviewed-by: shade
Backport-of: 2ce53e8848
2025-01-06 18:24:37 +00:00
Sorna Sarathi N
33971ecb6e 8346069: Add missing Classpath exception statements
Reviewed-by: kcr, iris, amitkumar
Backport-of: 09c29d1d42
2025-01-06 13:27:11 +00:00
Amit Kumar
4254e99ce2 8346847: [s390x] minimal build failure
Reviewed-by: clanger
Backport-of: 807f6f7fb8
2024-12-31 06:26:39 +00:00
Nizar Benalla
05c3769986 8337111: Bad HTML checker for generated documentation
8337113: Bad character checker for generated documentation
8337116: Internal links checker for generated documentation
8337114: DocType checker for generated documentation
8337117: External links checker for generated documentation

Reviewed-by: prappo
Backport-of: ed292318a9
2024-12-30 11:26:02 +00:00
Nizar Benalla
ab78b04cf6 8346667: Doccheck: warning about missing </span> before <h2>
Reviewed-by: prappo
Backport-of: 054c644ea6
2024-12-30 10:59:08 +00:00
Sorna Sarathi N
bed040191b 8344611: Add missing classpath exception
Reviewed-by: iris
Backport-of: 458979d83a
2024-12-20 18:13:13 +00:00
Patricio Chilano Mateo
5d138cbba0 8345266: java/util/concurrent/locks/StampedLock/OOMEInStampedLock.java JTREG_TEST_THREAD_FACTORY=Virtual fails with OOME
Reviewed-by: dholmes, alanb
Backport-of: 572ce269d0
2024-12-20 15:26:22 +00:00
Nizar Benalla
63aa68a7c6 8346128: Comparison build fails due to difference in LabelTarget.html
Reviewed-by: hannesw, liach
Backport-of: 2a68f74188
2024-12-20 15:05:22 +00:00
Justin Lu
f0ada9f34e 8345327: JDK 24 RDP1 L10n resource files update
Reviewed-by: naoto, dnguyen
Backport-of: fd0207d593
2024-12-19 22:08:57 +00:00
Hamlin Li
303736b038 8345669: RISC-V: fix client build failure due to AlignVector after JDK-8343827
Reviewed-by: fyang
Backport-of: a24b08fcb0
2024-12-19 09:27:16 +00:00
David Holmes
2c336299aa 8321818: vmTestbase/nsk/stress/strace/strace015.java failed with 'Cannot read the array length because "<local4>" is null'
Reviewed-by: lmesnik
Backport-of: ea50c54a14
2024-12-19 07:50:02 +00:00
SendaoYan
4aec2d4ef9 8338714: vmTestbase/nsk/jdb/kill/kill001/kill001.java fails with JTREG_TEST_THREAD_FACTORY=Virtual
Reviewed-by: dholmes
Backport-of: 414eb6bb83
2024-12-19 02:47:52 +00:00
Daniel Fuchs
b8249c5d90 8346017: Socket.connect specified to throw UHE for unresolved address is problematic for SOCKS V5 proxy
Reviewed-by: alanb
Backport-of: 9e8aa855fe
2024-12-18 18:05:16 +00:00
Paul Sandoz
0225372e0b 8346174: UMAX/UMIN are missing from XXXVector::reductionOperations
Reviewed-by: jbhateja
Backport-of: 31c3b19174
2024-12-18 17:23:51 +00:00
Jan Lahoda
2cc14faa21 8344647: Make java.se participate in the preview language feature requires transitive java.base
Reviewed-by: liach, vromero
Backport-of: d50b725ac0
2024-12-18 13:45:44 +00:00
Lance Andersen
f703b6e7b1 8346202: Correct typo in SQLPermission
Reviewed-by: iris
Backport-of: ab1dbd4089
2024-12-16 17:07:28 +00:00
Albert Mingkun Yang
297b21fb60 8345323: Parallel GC does not handle UseLargePages and UseNUMA gracefully
Reviewed-by: sjohanss
Backport-of: a9a5f7cb0a
2024-12-16 14:57:34 +00:00
Maurizio Cimadamore
67b8251679 8345944: JEP 492: extending local class in a different static context should not be allowed
8345953: JEP 492: instantiating local classes in a different static context should not be allowed

Reviewed-by: vromero
Backport-of: 0ad64234e2
2024-12-16 10:17:28 +00:00
Severin Gehwolf
6e8aad1ad4 8345573: Module dependencies not resolved from run-time image when --limit-module is being used
Reviewed-by: mchung
Backport-of: 11cd639842
2024-12-16 09:41:59 +00:00
Ioi Lam
4d6eccd9fc 8346159: Disable CDS AOTClassLinking tests for JVMCI due to JDK-8345635
Reviewed-by: ccheung
Backport-of: c2f0ef5f48
2024-12-16 06:17:11 +00:00
Nizar Benalla
6bc14d6b77 8345888: Broken links in the JDK 24 JavaDoc API documentation, build 27
Reviewed-by: psadhukhan
Backport-of: 9bd70ec806
2024-12-13 11:25:56 +00:00
Coleen Phillimore
897a8abecc 8346040: Zero interpreter build on Linux Aarch64 is broken
Reviewed-by: kbarrett
Backport-of: ef6e987a00
2024-12-12 22:24:36 +00:00
Roger Riggs
3b53ed7fb0 8345818: Fix SM cleanup of parsing of System property resource.bundle.debug
Reviewed-by: lancea
Backport-of: 4f855d1342
2024-12-12 17:27:54 +00:00
Adam Sotona
6fdfa72996 8345773: Class-File API debug printing capability
Reviewed-by: liach
Backport-of: f88c1c6ff8
2024-12-12 13:37:00 +00:00
Coleen Phillimore
950c8adfd7 8340212: -Xshare:off -XX:CompressedClassSpaceBaseAddress=0x40001000000 crashes on macos-aarch64
Reviewed-by: iklam
Backport-of: a6277bb521
2024-12-11 17:16:13 +00:00
Chen Liang
03bdee0f75 8342469: Improve API documentation for java.lang.classfile.instruction
Reviewed-by: asotona
Backport-of: 0f035545e5
2024-12-11 16:06:40 +00:00
Kevin Driver
4ecb28ccdc 8344924: Default CA certificates loaded despite request to use custom keystore
Reviewed-by: mullan
Backport-of: 4c39e9faa0
2024-12-10 21:14:37 +00:00
Michael McMahon
ba02e0bd1b 8345794: Backout doc change introduced by JDK-8235786
Reviewed-by: dfuchs
Backport-of: eff20a38c7
2024-12-10 16:58:13 +00:00
Per Minborg
253030a6d4 8345465: Fix performance regression on x64 after JDK-8345120
Reviewed-by: jvernee
Backport-of: 06c44dd568
2024-12-10 14:22:42 +00:00
Chen Liang
a81325433d 8334733: Remove obsolete @enablePreview from tests after JDK-8334714
Reviewed-by: mchung
Backport-of: 4966419550
2024-12-09 18:35:16 +00:00
Magnus Ihse Bursie
203422a8ed 8345424: Move FindDebuginfoFiles out of FileUtils.gmk
Reviewed-by: erikj
Backport-of: 5f30a8d90c
2024-12-09 15:57:55 +00:00
Fernando Guallini
8e9ba788ae 8345414: Google CAInterop test failures
Reviewed-by: rhalade
2024-12-06 18:41:47 +00:00
Matias Saavedra Silva
3aa07dbf14 8343890: SEGV crash in RunTimeClassInfo::klass
Reviewed-by: ccheung
Backport-of: bf0debc023
2024-12-05 22:01:31 +00:00
829 changed files with 20002 additions and 11128 deletions

View File

@@ -29,6 +29,7 @@ include $(SPEC)
include MakeBase.gmk
include CopyFiles.gmk
include DebugInfoUtils.gmk
include Execute.gmk
include Modules.gmk
include Utils.gmk

View File

@@ -29,6 +29,7 @@ include $(SPEC)
include MakeBase.gmk
include CopyFiles.gmk
include DebugInfoUtils.gmk
include Modules.gmk
include modules/LauncherCommon.gmk

View File

@@ -0,0 +1,58 @@
#
# Copyright (c) 2024, 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.
#
ifeq ($(_MAKEBASE_GMK), )
$(error You must include MakeBase.gmk prior to including DebugInfoUtils.gmk)
endif
################################################################################
#
# Common debuginfo utility functions
#
################################################################################
################################################################################
# Find native debuginfo files in a directory
#
# Param 1 - dir to find debuginfo files in
FindDebuginfoFiles = \
$(wildcard $(addprefix $1/*, $(DEBUGINFO_SUFFIXES)) \
$(addprefix $1/*/*, $(DEBUGINFO_SUFFIXES)) \
$(addprefix $1/*/*/*, $(DEBUGINFO_SUFFIXES)))
# Pick the correct debug info files to copy, either zipped or not.
ifeq ($(ZIP_EXTERNAL_DEBUG_SYMBOLS), true)
DEBUGINFO_SUFFIXES += .diz
else
DEBUGINFO_SUFFIXES := .debuginfo .pdb .map
# On Macosx, if debug symbols have not been zipped, find all files inside *.dSYM
# dirs.
ifeq ($(call isTargetOs, macosx), true)
$(call FillFindCache, \
$(SUPPORT_OUTPUTDIR)/modules_libs $(SUPPORT_OUTPUTDIR)/modules_cmds)
FindDebuginfoFiles = \
$(if $(wildcard $1), $(call containing, .dSYM/, $(call FindFiles, $1)))
endif
endif

View File

@@ -307,26 +307,3 @@ ifeq ($(DISABLE_CACHE_FIND), true)
else
FindFiles = $(CacheFindFiles)
endif
# Find native debuginfo files in a directory
#
# Param 1 - dir to find debuginfo files in
FindDebuginfoFiles = \
$(wildcard $(addprefix $1/*, $(DEBUGINFO_SUFFIXES)) \
$(addprefix $1/*/*, $(DEBUGINFO_SUFFIXES)) \
$(addprefix $1/*/*/*, $(DEBUGINFO_SUFFIXES)))
# Pick the correct debug info files to copy, either zipped or not.
ifeq ($(ZIP_EXTERNAL_DEBUG_SYMBOLS), true)
DEBUGINFO_SUFFIXES += .diz
else
DEBUGINFO_SUFFIXES := .debuginfo .pdb .map
# On Macosx, if debug symbols have not been zipped, find all files inside *.dSYM
# dirs.
ifeq ($(call isTargetOs, macosx), true)
$(call FillFindCache, \
$(SUPPORT_OUTPUTDIR)/modules_libs $(SUPPORT_OUTPUTDIR)/modules_cmds)
FindDebuginfoFiles = \
$(if $(wildcard $1), $(call containing, .dSYM/, $(call FindFiles, $1)))
endif
endif

View File

@@ -1,5 +1,5 @@
#
# Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2014, 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
@@ -92,7 +92,7 @@ SRC_SUBDIRS += share/classes
SPEC_SUBDIRS += share/specs
MAN_SUBDIRS += share/man
MAN_SUBDIRS += share/man windows/man
# Find all module-info.java files for the current build target platform and
# configuration.

View File

@@ -39,4 +39,4 @@ DEFAULT_VERSION_CLASSFILE_MINOR=0
DEFAULT_VERSION_DOCS_API_SINCE=11
DEFAULT_ACCEPTABLE_BOOT_VERSIONS="23 24"
DEFAULT_JDK_SOURCE_TARGET_VERSION=24
DEFAULT_PROMOTED_VERSION_PRE=ea
DEFAULT_PROMOTED_VERSION_PRE=

View File

@@ -1,5 +1,5 @@
#
# Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2021, 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
@@ -64,7 +64,7 @@ ifeq ($(call isTargetOs, linux)+$(call isTargetCpu, aarch64)+$(INCLUDE_COMPILER2
EXTRA_SRC := libsleef/generated, \
DISABLED_WARNINGS_gcc := unused-function sign-compare tautological-compare ignored-qualifiers, \
DISABLED_WARNINGS_clang := unused-function sign-compare tautological-compare ignored-qualifiers, \
CFLAGS := $(SVE_CFLAGS), \
vector_math_sve.c_CFLAGS := $(SVE_CFLAGS), \
))
TARGETS += $(BUILD_LIBSLEEF)

View File

@@ -24,12 +24,14 @@
*/
#include "precompiled.hpp"
#include "asm/assembler.hpp"
#include "asm/macroAssembler.hpp"
#include "logging/log.hpp"
#include "oops/compressedKlass.hpp"
#include "memory/metaspace.hpp"
#include "runtime/java.hpp"
#include "runtime/os.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/formatBuffer.hpp"
// Helper function; reserve at an address that is compatible with EOR
static char* reserve_at_eor_compatible_address(size_t size, bool aslr) {
@@ -79,6 +81,7 @@ static char* reserve_at_eor_compatible_address(size_t size, bool aslr) {
}
return result;
}
char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size_t size, bool aslr, bool optimize_for_zero_base) {
char* result = nullptr;
@@ -117,3 +120,12 @@ char* CompressedKlassPointers::reserve_address_space_for_compressed_classes(size
return result;
}
bool CompressedKlassPointers::check_klass_decode_mode(address base, int shift, const size_t range) {
return MacroAssembler::check_klass_decode_mode(base, shift, range);
}
bool CompressedKlassPointers::set_klass_decode_mode() {
const size_t range = klass_range_end() - base();
return MacroAssembler::set_klass_decode_mode(_base, _shift, range);
}

View File

@@ -5291,32 +5291,47 @@ void MacroAssembler::decode_heap_oop_not_null(Register dst, Register src) {
MacroAssembler::KlassDecodeMode MacroAssembler::_klass_decode_mode(KlassDecodeNone);
MacroAssembler::KlassDecodeMode MacroAssembler::klass_decode_mode() {
assert(UseCompressedClassPointers, "not using compressed class pointers");
assert(Metaspace::initialized(), "metaspace not initialized yet");
assert(_klass_decode_mode != KlassDecodeNone, "should be initialized");
return _klass_decode_mode;
}
if (_klass_decode_mode != KlassDecodeNone) {
return _klass_decode_mode;
}
MacroAssembler::KlassDecodeMode MacroAssembler::klass_decode_mode(address base, int shift, const size_t range) {
assert(UseCompressedClassPointers, "not using compressed class pointers");
if (CompressedKlassPointers::base() == nullptr) {
return (_klass_decode_mode = KlassDecodeZero);
// KlassDecodeMode shouldn't be set already.
assert(_klass_decode_mode == KlassDecodeNone, "set once");
if (base == nullptr) {
return KlassDecodeZero;
}
if (operand_valid_for_logical_immediate(
/*is32*/false, (uint64_t)CompressedKlassPointers::base())) {
const size_t range = CompressedKlassPointers::klass_range_end() - CompressedKlassPointers::base();
/*is32*/false, (uint64_t)base)) {
const uint64_t range_mask = right_n_bits(log2i_ceil(range));
if (((uint64_t)CompressedKlassPointers::base() & range_mask) == 0) {
return (_klass_decode_mode = KlassDecodeXor);
if (((uint64_t)base & range_mask) == 0) {
return KlassDecodeXor;
}
}
const uint64_t shifted_base =
(uint64_t)CompressedKlassPointers::base() >> CompressedKlassPointers::shift();
guarantee((shifted_base & 0xffff0000ffffffff) == 0,
"compressed class base bad alignment");
(uint64_t)base >> shift;
if ((shifted_base & 0xffff0000ffffffff) == 0) {
return KlassDecodeMovk;
}
return (_klass_decode_mode = KlassDecodeMovk);
// No valid encoding.
return KlassDecodeNone;
}
// Check if one of the above decoding modes will work for given base, shift and range.
bool MacroAssembler::check_klass_decode_mode(address base, int shift, const size_t range) {
return klass_decode_mode(base, shift, range) != KlassDecodeNone;
}
bool MacroAssembler::set_klass_decode_mode(address base, int shift, const size_t range) {
_klass_decode_mode = klass_decode_mode(base, shift, range);
return _klass_decode_mode != KlassDecodeNone;
}
void MacroAssembler::encode_klass_not_null(Register dst, Register src) {

View File

@@ -94,11 +94,22 @@ class MacroAssembler: public Assembler {
KlassDecodeMovk
};
KlassDecodeMode klass_decode_mode();
// Calculate decoding mode based on given parameters, used for checking then ultimately setting.
static KlassDecodeMode klass_decode_mode(address base, int shift, const size_t range);
private:
static KlassDecodeMode _klass_decode_mode;
// Returns above setting with asserts
static KlassDecodeMode klass_decode_mode();
public:
// Checks the decode mode and returns false if not compatible with preferred decoding mode.
static bool check_klass_decode_mode(address base, int shift, const size_t range);
// Sets the decode mode and returns false if cannot be set.
static bool set_klass_decode_mode(address base, int shift, const size_t range);
public:
MacroAssembler(CodeBuffer* code) : Assembler(code) {}

View File

@@ -189,7 +189,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dsin());
}
__ call(fn);
__ rt_call(fn);
__ mv(ra, x9);
break;
case Interpreter::java_lang_math_cos :
@@ -202,7 +202,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dcos());
}
__ call(fn);
__ rt_call(fn);
__ mv(ra, x9);
break;
case Interpreter::java_lang_math_tan :
@@ -215,7 +215,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dtan());
}
__ call(fn);
__ rt_call(fn);
__ mv(ra, x9);
break;
case Interpreter::java_lang_math_log :
@@ -228,7 +228,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dlog());
}
__ call(fn);
__ rt_call(fn);
__ mv(ra, x9);
break;
case Interpreter::java_lang_math_log10 :
@@ -241,7 +241,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dlog10());
}
__ call(fn);
__ rt_call(fn);
__ mv(ra, x9);
break;
case Interpreter::java_lang_math_exp :
@@ -254,7 +254,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dexp());
}
__ call(fn);
__ rt_call(fn);
__ mv(ra, x9);
break;
case Interpreter::java_lang_math_pow :
@@ -268,7 +268,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M
} else {
fn = CAST_FROM_FN_PTR(address, StubRoutines::dpow());
}
__ call(fn);
__ rt_call(fn);
__ mv(ra, x9);
break;
case Interpreter::java_lang_math_fmaD :

View File

@@ -154,10 +154,6 @@ void VM_Version::common_initialize() {
unaligned_access.value() != MISALIGNED_FAST);
}
if (FLAG_IS_DEFAULT(AlignVector)) {
FLAG_SET_DEFAULT(AlignVector, AvoidUnalignedAccesses);
}
// See JDK-8026049
// This machine has fast unaligned memory accesses
if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) {
@@ -440,6 +436,10 @@ void VM_Version::c2_initialize() {
warning("AES/CTR intrinsics are not available on this CPU");
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
}
if (FLAG_IS_DEFAULT(AlignVector)) {
FLAG_SET_DEFAULT(AlignVector, AvoidUnalignedAccesses);
}
}
#endif // COMPILER2

View File

@@ -308,6 +308,12 @@ void VM_Version::initialize() {
if (FLAG_IS_DEFAULT(UseMontgomerySquareIntrinsic)) {
FLAG_SET_DEFAULT(UseMontgomerySquareIntrinsic, true);
}
// The OptoScheduling information is not maintained in s390.ad.
if (OptoScheduling) {
warning("OptoScheduling is not supported on this CPU.");
FLAG_SET_DEFAULT(OptoScheduling, false);
}
#endif
if (FLAG_IS_DEFAULT(UsePopCountInstruction)) {
FLAG_SET_DEFAULT(UsePopCountInstruction, true);
@@ -323,12 +329,6 @@ void VM_Version::initialize() {
if (FLAG_IS_DEFAULT(UseUnalignedAccesses)) {
FLAG_SET_DEFAULT(UseUnalignedAccesses, true);
}
// The OptoScheduling information is not maintained in s390.ad.
if (OptoScheduling) {
warning("OptoScheduling is not supported on this CPU.");
FLAG_SET_DEFAULT(OptoScheduling, false);
}
}

View File

@@ -38,7 +38,7 @@ enum platform_dependent_constants {
// AVX512 intrinsics add more code in 64-bit VM,
// Windows have more code to save/restore registers
_compiler_stubs_code_size = 20000 LP64_ONLY(+47000) WINDOWS_ONLY(+2000),
_final_stubs_code_size = 10000 LP64_ONLY(+20000) WINDOWS_ONLY(+2000) ZGC_ONLY(+20000)
_final_stubs_code_size = 10000 LP64_ONLY(+20000) WINDOWS_ONLY(+22000) ZGC_ONLY(+20000)
};
class x86 {

View File

@@ -420,6 +420,11 @@ void CDSConfig::check_flag_aliases() {
bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_flag_cmd_line) {
check_flag_aliases();
if (!FLAG_IS_DEFAULT(AOTMode)) {
// Using any form of the new AOTMode switch enables enhanced optimizations.
FLAG_SET_ERGO_IF_DEFAULT(AOTClassLinking, true);
}
if (AOTClassLinking) {
// If AOTClassLinking is specified, enable all AOT optimizations by default.
FLAG_SET_ERGO_IF_DEFAULT(AOTInvokeDynamicLinking, true);

View File

@@ -2511,6 +2511,13 @@ bool FileMapInfo::validate_aot_class_linking() {
log_error(cds)("CDS archive has aot-linked classes. It cannot be used with -Djava.security.manager=%s.", prop);
return false;
}
#if INCLUDE_JVMTI
if (Arguments::has_jdwp_agent()) {
log_error(cds)("CDS archive has aot-linked classes. It cannot be used with JDWP agent");
return false;
}
#endif
}
return true;

View File

@@ -145,15 +145,16 @@ size_t MetaspaceShared::core_region_alignment() {
}
static bool shared_base_valid(char* shared_base) {
// We check user input for SharedBaseAddress at dump time. We must weed out values
// we already know to be invalid later.
// We check user input for SharedBaseAddress at dump time.
// At CDS runtime, "shared_base" will be the (attempted) mapping start. It will also
// be the encoding base, since the the headers of archived base objects (and with Lilliput,
// the prototype mark words) carry pre-computed narrow Klass IDs that refer to the mapping
// start as base.
//
// Therefore, "shared_base" must be later usable as encoding base.
// On AARCH64, The "shared_base" may not be later usable as encoding base, depending on the
// total size of the reserved area and the precomputed_narrow_klass_shift. This is checked
// before reserving memory. Here we weed out values already known to be invalid later.
return AARCH64_ONLY(is_aligned(shared_base, 4 * G)) NOT_AARCH64(true);
}
@@ -985,8 +986,10 @@ bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) {
ik->external_name());
CLEAR_PENDING_EXCEPTION;
SystemDictionaryShared::set_class_has_failed_verification(ik);
} else {
assert(!SystemDictionaryShared::has_class_failed_verification(ik), "sanity");
ik->compute_has_loops_flag_for_methods();
}
ik->compute_has_loops_flag_for_methods();
BytecodeVerificationLocal = saved;
return true;
} else {
@@ -1486,6 +1489,15 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
const size_t total_range_size =
archive_space_size + gap_size + class_space_size;
// Test that class space base address plus shift can be decoded by aarch64, when restored.
const int precomputed_narrow_klass_shift = ArchiveBuilder::precomputed_narrow_klass_shift();
if (!CompressedKlassPointers::check_klass_decode_mode(base_address, precomputed_narrow_klass_shift,
total_range_size)) {
log_info(cds)("CDS initialization: Cannot use SharedBaseAddress " PTR_FORMAT " with precomputed shift %d.",
p2i(base_address), precomputed_narrow_klass_shift);
use_archive_base_addr = false;
}
assert(total_range_size > ccs_begin_offset, "must be");
if (use_windows_memory_mapping() && use_archive_base_addr) {
if (base_address != nullptr) {
@@ -1525,7 +1537,7 @@ char* MetaspaceShared::reserve_address_space_for_archives(FileMapInfo* static_ma
}
// Paranoid checks:
assert(base_address == nullptr || (address)total_space_rs.base() == base_address,
assert(!use_archive_base_addr || (address)total_space_rs.base() == base_address,
"Sanity (" PTR_FORMAT " vs " PTR_FORMAT ")", p2i(base_address), p2i(total_space_rs.base()));
assert(is_aligned(total_space_rs.base(), base_address_alignment), "Sanity");
assert(total_space_rs.size() == total_range_size, "Sanity");

View File

@@ -76,10 +76,13 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
}
InstanceKlass* RunTimeClassInfo::klass() const {
if (ArchiveBuilder::is_active() && ArchiveBuilder::current()->is_in_buffer_space((address)this)) {
return ArchiveBuilder::current()->offset_to_buffered<InstanceKlass*>(_klass_offset);
} else {
if (MetaspaceShared::is_in_shared_metaspace(this)) {
// <this> is inside a mmaped CDS archive.
return ArchiveUtils::offset_to_archived_address<InstanceKlass*>(_klass_offset);
} else {
// <this> is a temporary copy of a RunTimeClassInfo that's being initialized
// by the ArchiveBuilder.
return ArchiveBuilder::current()->offset_to_buffered<InstanceKlass*>(_klass_offset);
}
}

View File

@@ -327,6 +327,13 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
if (!k->is_linked()) {
if (has_class_failed_verification(k)) {
return warn_excluded(k, "Failed verification");
} else if (CDSConfig::is_dumping_aot_linked_classes()) {
// Most loaded classes should have been speculatively linked by MetaspaceShared::link_class_for_cds().
// However, we do not speculatively link old classes, as they are not recorded by
// SystemDictionaryShared::record_linking_constraint(). As a result, such an unlinked
// class may fail to verify in AOTLinkedClassBulkLoader::init_required_classes_for_loader(),
// causing the JVM to fail at bootstrap.
return warn_excluded(k, "Unlinked class not supported by AOTClassLinking");
}
} else {
if (!k->can_be_verified_at_dumptime()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@@ -205,7 +205,7 @@ void CodeCache::initialize_heaps() {
const bool cache_size_set = FLAG_IS_CMDLINE(ReservedCodeCacheSize);
const size_t ps = page_size(false, 8);
const size_t min_size = MAX2(os::vm_allocation_granularity(), ps);
const size_t min_cache_size = CompilerConfig::min_code_cache_size(); // Make sure we have enough space for VM internal code
const size_t min_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3); // Make sure we have enough space for VM internal code
size_t cache_size = align_up(ReservedCodeCacheSize, min_size);
// Prerequisites

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 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
@@ -455,7 +455,7 @@ void CompilationPolicy::initialize() {
c2_size = C2Compiler::initial_code_buffer_size();
#endif
size_t buffer_size = c1_only ? c1_size : (c1_size/3 + 2*c2_size/3);
int max_count = (ReservedCodeCacheSize - (int)CompilerConfig::min_code_cache_size()) / (int)buffer_size;
int max_count = (ReservedCodeCacheSize - (CodeCacheMinimumUseSpace DEBUG_ONLY(* 3))) / (int)buffer_size;
if (count > max_count) {
// Lower the compiler count such that all buffers fit into the code cache
count = MAX2(max_count, c1_only ? 1 : 2);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@@ -475,7 +475,8 @@ void CompilerConfig::set_jvmci_specific_flags() {
bool CompilerConfig::check_args_consistency(bool status) {
// Check lower bounds of the code cache
size_t min_code_cache_size = CompilerConfig::min_code_cache_size();
// Template Interpreter code is approximately 3X larger in debug builds.
uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3);
if (ReservedCodeCacheSize < InitialCodeCacheSize) {
jio_fprintf(defaultStream::error_stream(),
"Invalid ReservedCodeCacheSize: %dK. Must be at least InitialCodeCacheSize=%dK.\n",

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@@ -148,8 +148,6 @@ public:
inline static bool is_c2_or_jvmci_compiler_only();
inline static bool is_c2_or_jvmci_compiler_enabled();
inline static size_t min_code_cache_size();
private:
static bool is_compilation_mode_selected();
static void set_compilation_policy_flags();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 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
@@ -25,12 +25,6 @@
#ifndef SHARE_COMPILER_COMPILERDEFINITIONS_INLINE_HPP
#define SHARE_COMPILER_COMPILERDEFINITIONS_INLINE_HPP
#ifdef COMPILER1
#include "c1/c1_Compiler.hpp"
#endif
#ifdef COMPILER2
#include "opto/c2compiler.hpp"
#endif
#include "compiler/compilerDefinitions.hpp"
#include "compiler/compiler_globals.hpp"
@@ -138,13 +132,4 @@ inline bool CompilerConfig::is_c2_or_jvmci_compiler_enabled() {
return is_c2_enabled() || is_jvmci_compiler_enabled();
}
inline size_t CompilerConfig::min_code_cache_size() {
size_t min_code_cache_size = CodeCacheMinimumUseSpace;
// Template Interpreter code is approximately 3X larger in debug builds.
DEBUG_ONLY(min_code_cache_size *= 3);
COMPILER1_PRESENT(min_code_cache_size += Compiler::code_buffer_size());
COMPILER2_PRESENT(min_code_cache_size += C2Compiler::initial_code_buffer_size());
return min_code_cache_size;
}
#endif // SHARE_COMPILER_COMPILERDEFINITIONS_INLINE_HPP

View File

@@ -140,8 +140,8 @@ void VM_GC_Operation::doit_epilogue() {
}
bool VM_GC_HeapInspection::doit_prologue() {
if (_full_gc && UseZGC) {
// ZGC cannot perform a synchronous GC cycle from within the VM thread.
if (_full_gc && (UseZGC || UseShenandoahGC)) {
// ZGC and Shenandoah cannot perform a synchronous GC cycle from within the VM thread.
// So VM_GC_HeapInspection::collect() is a noop. To respect the _full_gc
// flag a synchronous GC cycle is performed from the caller thread in the
// prologue.

View File

@@ -37,7 +37,11 @@ size_t MinNewSize = 0;
size_t MinOldSize = 0;
size_t MaxOldSize = 0;
size_t OldSize = 0;
// If InitialHeapSize or MinHeapSize is not set on cmdline, this variable,
// together with NewSize, is used to derive them.
// Using the same value when it was a configurable flag to avoid breakage.
// See more in JDK-8346005
size_t OldSize = ScaleForWordSize(4*M);
size_t GenAlignment = 0;

View File

@@ -180,8 +180,8 @@ void ShenandoahGenerationalHeap::gc_threads_do(ThreadClosure* tcl) const {
}
void ShenandoahGenerationalHeap::stop() {
regulator_thread()->stop();
ShenandoahHeap::stop();
regulator_thread()->stop();
}
void ShenandoahGenerationalHeap::evacuate_collection_set(bool concurrent) {

View File

@@ -538,7 +538,6 @@ ShenandoahHeap::ShenandoahHeap(ShenandoahCollectorPolicy* policy) :
_pacer(nullptr),
_verifier(nullptr),
_phase_timings(nullptr),
_mmu_tracker(),
_monitoring_support(nullptr),
_memory_pool(nullptr),
_stw_memory_manager("Shenandoah Pauses"),
@@ -632,6 +631,8 @@ public:
void ShenandoahHeap::post_initialize() {
CollectedHeap::post_initialize();
// Schedule periodic task to report on gc thread CPU utilization
_mmu_tracker.initialize();
MutexLocker ml(Threads_lock);
@@ -1467,6 +1468,18 @@ size_t ShenandoahHeap::max_tlab_size() const {
return ShenandoahHeapRegion::max_tlab_size_words();
}
void ShenandoahHeap::collect_as_vm_thread(GCCause::Cause cause) {
// These requests are ignored because we can't easily have Shenandoah jump into
// a synchronous (degenerated or full) cycle while it is in the middle of a concurrent
// cycle. We _could_ cancel the concurrent cycle and then try to run a cycle directly
// on the VM thread, but this would confuse the control thread mightily and doesn't
// seem worth the trouble. Instead, we will have the caller thread run (and wait for) a
// concurrent cycle in the prologue of the heap inspect/dump operation. This is how
// other concurrent collectors in the JVM handle this scenario as well.
assert(Thread::current()->is_VM_thread(), "Should be the VM thread");
guarantee(cause == GCCause::_heap_dump || cause == GCCause::_heap_inspection, "Invalid cause");
}
void ShenandoahHeap::collect(GCCause::Cause cause) {
control_thread()->request_gc(cause);
}
@@ -1547,7 +1560,9 @@ void ShenandoahHeap::set_active_generation() {
void ShenandoahHeap::on_cycle_start(GCCause::Cause cause, ShenandoahGeneration* generation) {
shenandoah_policy()->record_collection_cause(cause);
assert(gc_cause() == GCCause::_no_gc, "Over-writing cause");
const GCCause::Cause current = gc_cause();
assert(current == GCCause::_no_gc, "Over-writing cause: %s, with: %s",
GCCause::to_string(current), GCCause::to_string(cause));
assert(_gc_generation == nullptr, "Over-writing _gc_generation");
set_gc_cause(cause);
@@ -2084,6 +2099,9 @@ void ShenandoahHeap::stop() {
// Step 0. Notify policy to disable event recording and prevent visiting gc threads during shutdown
_shenandoah_policy->record_shutdown();
// Step 0a. Stop reporting on gc thread cpu utilization
mmu_tracker()->stop();
// Step 1. Notify control thread that we are in shutdown.
// Note that we cannot do that with stop(), because stop() is blocking and waits for the actual shutdown.
// Doing stop() here would wait for the normal GC cycle to complete, never falling through to cancel below.

View File

@@ -608,6 +608,7 @@ public:
MemRegion reserved_region() const { return _reserved; }
bool is_in_reserved(const void* addr) const { return _reserved.contains(addr); }
void collect_as_vm_thread(GCCause::Cause cause) override;
void collect(GCCause::Cause cause) override;
void do_full_collection(bool clear_all_soft_refs) override;

View File

@@ -93,11 +93,6 @@ size_t ShenandoahGenerationalMemoryPool::used_in_bytes() {
return _generation->used();
}
size_t ShenandoahGenerationalMemoryPool::max_size() const {
return _generation->max_capacity();
}
ShenandoahYoungGenMemoryPool::ShenandoahYoungGenMemoryPool(ShenandoahHeap* heap) :
ShenandoahGenerationalMemoryPool(heap,
"Shenandoah Young Gen",

View File

@@ -55,7 +55,6 @@ public:
explicit ShenandoahGenerationalMemoryPool(ShenandoahHeap* heap, const char* name, ShenandoahGeneration* generation);
MemoryUsage get_memory_usage() override;
size_t used_in_bytes() override;
size_t max_size() const override;
};
class ShenandoahYoungGenMemoryPool : public ShenandoahGenerationalMemoryPool {

View File

@@ -48,6 +48,7 @@ class ThreadTimeAccumulator : public ThreadClosure {
size_t total_time;
ThreadTimeAccumulator() : total_time(0) {}
void do_thread(Thread* thread) override {
assert(!thread->has_terminated(), "Cannot get cpu time for terminated thread: " UINTX_FORMAT, thread->osthread()->thread_id_for_printing());
total_time += os::thread_cpu_time(thread);
}
};
@@ -65,7 +66,6 @@ ShenandoahMmuTracker::ShenandoahMmuTracker() :
}
ShenandoahMmuTracker::~ShenandoahMmuTracker() {
_mmu_periodic_task->disenroll();
delete _mmu_periodic_task;
}
@@ -175,6 +175,10 @@ void ShenandoahMmuTracker::report() {
log_debug(gc)("Periodic Sample: GCU = %.3f%%, MU = %.3f%% during most recent %.1fs", gcu * 100, mu * 100, time_delta);
}
void ShenandoahMmuTracker::stop() const {
_mmu_periodic_task->disenroll();
}
void ShenandoahMmuTracker::initialize() {
// initialize static data
_active_processors = os::initial_active_processor_count();

View File

@@ -101,6 +101,10 @@ public:
// GCPauseIntervalMillis and defaults to 5 seconds. This method computes
// the MMU over the elapsed interval and records it in a running average.
void report();
// Unenrolls the periodic task that collects CPU utilization for GC threads. This must happen _before_ the
// gc threads are stopped and terminated.
void stop() const;
};
#endif //SHARE_GC_SHENANDOAH_SHENANDOAHMMUTRACKER_HPP

View File

@@ -559,7 +559,9 @@ static const Node* get_base_and_offset(const MachNode* mach, intptr_t& offset) {
// The memory address is computed by 'base' and fed to 'mach' via an
// indirect memory operand (indicated by offset == 0). The ultimate base and
// offset can be fetched directly from the inputs and Ideal type of 'base'.
offset = base->bottom_type()->isa_oopptr()->offset();
const TypeOopPtr* oopptr = base->bottom_type()->isa_oopptr();
if (oopptr == nullptr) return nullptr;
offset = oopptr->offset();
// Even if 'base' is not an Ideal AddP node anymore, Matcher::ReduceInst()
// guarantees that the base address is still available at the same slot.
base = base->in(AddPNode::Base);

View File

@@ -30,6 +30,7 @@
#include "runtime/java.hpp"
#include "runtime/os.hpp"
#include "utilities/debug.hpp"
#include "utilities/formatBuffer.hpp"
#include "utilities/globalDefinitions.hpp"
#include "utilities/ostream.hpp"
@@ -176,6 +177,12 @@ void CompressedKlassPointers::initialize_for_given_encoding(address addr, size_t
calc_lowest_highest_narrow_klass_id();
// This has already been checked for SharedBaseAddress and if this fails, it's a bug in the allocation code.
if (!set_klass_decode_mode()) {
fatal("base=" PTR_FORMAT " given with shift %d, cannot be used to encode class pointers",
p2i(_base), _shift);
}
DEBUG_ONLY(sanity_check_after_initialization();)
}
@@ -267,6 +274,20 @@ void CompressedKlassPointers::initialize(address addr, size_t len) {
calc_lowest_highest_narrow_klass_id();
// Initialize klass decode mode and check compability with decode instructions
if (!set_klass_decode_mode()) {
// Give fatal error if this is a specified address
if ((address)CompressedClassSpaceBaseAddress == _base) {
vm_exit_during_initialization(
err_msg("CompressedClassSpaceBaseAddress=" PTR_FORMAT " given with shift %d, cannot be used to encode class pointers",
CompressedClassSpaceBaseAddress, _shift));
} else {
// If this fails, it's a bug in the allocation code.
fatal("CompressedClassSpaceBaseAddress=" PTR_FORMAT " given with shift %d, cannot be used to encode class pointers",
p2i(_base), _shift);
}
}
#ifdef ASSERT
sanity_check_after_initialization();
#endif

View File

@@ -258,6 +258,15 @@ public:
is_aligned(addr, klass_alignment_in_bytes());
}
#if defined(AARCH64) && !defined(ZERO)
// Check that with the given base, shift and range, aarch64 code can encode and decode the klass pointer.
static bool check_klass_decode_mode(address base, int shift, const size_t range);
// Called after initialization.
static bool set_klass_decode_mode();
#else
static bool check_klass_decode_mode(address base, int shift, const size_t range) { return true; }
static bool set_klass_decode_mode() { return true; }
#endif
};
#endif // SHARE_OOPS_COMPRESSEDKLASS_HPP

View File

@@ -395,159 +395,9 @@ Node* AddNode::IdealIL(PhaseGVN* phase, bool can_reshape, BasicType bt) {
}
}
// Convert a + a + ... + a into a*n
Node* serial_additions = convert_serial_additions(phase, bt);
if (serial_additions != nullptr) {
return serial_additions;
}
return AddNode::Ideal(phase, can_reshape);
}
// Try to convert a serial of additions into a single multiplication. Also convert `(a * CON) + a` to `(CON + 1) * a` as
// a side effect. On success, a new MulNode is returned.
Node* AddNode::convert_serial_additions(PhaseGVN* phase, BasicType bt) {
// We need to make sure that the current AddNode is not part of a MulNode that has already been optimized to a
// power-of-2 addition (e.g., 3 * a => (a << 2) + a). Without this check, GVN would keep trying to optimize the same
// node and can't progress. For example, 3 * a => (a << 2) + a => 3 * a => (a << 2) + a => ...
if (find_power_of_two_addition_pattern(this, bt, nullptr) != nullptr) {
return nullptr;
}
Node* in1 = in(1);
Node* in2 = in(2);
jlong multiplier;
// While multiplications can be potentially optimized to power-of-2 subtractions (e.g., a * 7 => (a << 3) - a),
// (x - y) + y => x is already handled by the Identity() methods. So, we don't need to check for that pattern here.
if (find_simple_addition_pattern(in1, bt, &multiplier) == in2
|| find_simple_lshift_pattern(in1, bt, &multiplier) == in2
|| find_simple_multiplication_pattern(in1, bt, &multiplier) == in2
|| find_power_of_two_addition_pattern(in1, bt, &multiplier) == in2) {
multiplier++; // +1 for the in2 term
Node* con = (bt == T_INT)
? (Node*) phase->intcon((jint) multiplier) // intentional type narrowing to allow overflow at max_jint
: (Node*) phase->longcon(multiplier);
return MulNode::make(con, in2, bt);
}
return nullptr;
}
// Try to match `a + a`. On success, return `a` and set `2` as `multiplier`.
// The method matches `n` for pattern: AddNode(a, a).
Node* AddNode::find_simple_addition_pattern(Node* n, BasicType bt, jlong* multiplier) {
if (n->Opcode() == Op_Add(bt) && n->in(1) == n->in(2)) {
*multiplier = 2;
return n->in(1);
}
return nullptr;
}
// Try to match `a << CON`. On success, return `a` and set `1 << CON` as `multiplier`.
// Match `n` for pattern: LShiftNode(a, CON).
// Note that the power-of-2 multiplication optimization could potentially convert a MulNode to this pattern.
Node* AddNode::find_simple_lshift_pattern(Node* n, BasicType bt, jlong* multiplier) {
// Note that power-of-2 multiplication optimization could potentially convert a MulNode to this pattern
if (n->Opcode() == Op_LShift(bt) && n->in(2)->is_Con()) {
Node* con = n->in(2);
if (con->is_top()) {
return nullptr;
}
*multiplier = ((jlong) 1 << con->get_int());
return n->in(1);
}
return nullptr;
}
// Try to match `CON * a`. On success, return `a` and set `CON` as `multiplier`.
// Match `n` for patterns:
// - MulNode(CON, a)
// - MulNode(a, CON)
Node* AddNode::find_simple_multiplication_pattern(Node* n, BasicType bt, jlong* multiplier) {
// This optimization technically only produces MulNode(CON, a), but we might as match MulNode(a, CON), too.
if (n->Opcode() == Op_Mul(bt) && (n->in(1)->is_Con() || n->in(2)->is_Con())) {
Node* con = n->in(1);
Node* base = n->in(2);
// swap ConNode to lhs for easier matching
if (!con->is_Con()) {
swap(con, base);
}
if (con->is_top()) {
return nullptr;
}
*multiplier = con->get_integer_as_long(bt);
return base;
}
return nullptr;
}
// Try to match `(a << CON1) + (a << CON2)`. On success, return `a` and set `(1 << CON1) + (1 << CON2)` as `multiplier`.
// Match `n` for patterns:
// - AddNode(LShiftNode(a, CON), LShiftNode(a, CON)/a)
// - AddNode(LShiftNode(a, CON)/a, LShiftNode(a, CON))
// given that lhs is different from rhs.
// Note that one of the term of the addition could simply be `a` (i.e., a << 0). Calling this function with `multiplier`
// being null is safe.
Node* AddNode::find_power_of_two_addition_pattern(Node* n, BasicType bt, jlong* multiplier) {
if (n->Opcode() == Op_Add(bt) && n->in(1) != n->in(2)) {
Node* lhs = n->in(1);
Node* rhs = n->in(2);
// swap LShiftNode to lhs for easier matching
if (lhs->Opcode() != Op_LShift(bt)) {
swap(lhs, rhs);
}
// AddNode(LShiftNode(a, CON), *)?
if (lhs->Opcode() != Op_LShift(bt) || !lhs->in(2)->is_Con()) {
return nullptr;
}
jlong lhs_multiplier = 0;
if (multiplier != nullptr) {
Node* con = lhs->in(2);
if (con->is_top()) {
return nullptr;
}
lhs_multiplier = (jlong) 1 << con->get_int();
}
// AddNode(LShiftNode(a, CON), a)?
if (lhs->in(1) == rhs) {
if (multiplier != nullptr) {
*multiplier = lhs_multiplier + 1;
}
return rhs;
}
// AddNode(LShiftNode(a, CON), LShiftNode(a, CON2))?
if (rhs->Opcode() == Op_LShift(bt) && lhs->in(1) == rhs->in(1) && rhs->in(2)->is_Con()) {
if (multiplier != nullptr) {
Node* con = rhs->in(2);
if (con->is_top()) {
return nullptr;
}
*multiplier = lhs_multiplier + ((jlong) 1 << con->get_int());
}
return lhs->in(1);
}
return nullptr;
}
return nullptr;
}
Node* AddINode::Ideal(PhaseGVN* phase, bool can_reshape) {
Node* in1 = in(1);

View File

@@ -42,13 +42,6 @@ typedef const Pair<Node*, jint> ConstAddOperands;
// by virtual functions.
class AddNode : public Node {
virtual uint hash() const;
Node* convert_serial_additions(PhaseGVN* phase, BasicType bt);
static Node* find_simple_addition_pattern(Node* n, BasicType bt, jlong* multiplier);
static Node* find_simple_lshift_pattern(Node* n, BasicType bt, jlong* multiplier);
static Node* find_simple_multiplication_pattern(Node* n, BasicType bt, jlong* multiplier);
static Node* find_power_of_two_addition_pattern(Node* n, BasicType bt, jlong* multiplier);
public:
AddNode( Node *in1, Node *in2 ) : Node(nullptr,in1,in2) {
init_class_id(Class_Add);

View File

@@ -933,6 +933,9 @@ JVMState* PredictedCallGenerator::generate(JVMState* jvms) {
// Make the hot call:
JVMState* new_jvms = _if_hit->generate(kit.sync_jvms());
if (kit.failing()) {
return nullptr;
}
if (new_jvms == nullptr) {
// Inline failed, so make a direct call.
assert(_if_hit->is_inline(), "must have been a failed inline");
@@ -1260,6 +1263,9 @@ JVMState* PredicatedIntrinsicGenerator::generate(JVMState* jvms) {
PreserveJVMState pjvms(&kit);
// Generate intrinsic code:
JVMState* new_jvms = _intrinsic->generate(kit.sync_jvms());
if (kit.failing()) {
return nullptr;
}
if (new_jvms == nullptr) {
// Intrinsic failed, use normal compilation path for this predicate.
slow_region->add_req(kit.control());

View File

@@ -4262,7 +4262,7 @@ bool LibraryCallKit::inline_native_subtype_check() {
//---------------------generate_array_guard_common------------------------
Node* LibraryCallKit::generate_array_guard_common(Node* kls, RegionNode* region,
bool obj_array, bool not_array) {
bool obj_array, bool not_array, Node** obj) {
if (stopped()) {
return nullptr;
@@ -4304,7 +4304,19 @@ Node* LibraryCallKit::generate_array_guard_common(Node* kls, RegionNode* region,
// invert the test if we are looking for a non-array
if (not_array) btest = BoolTest(btest).negate();
Node* bol = _gvn.transform(new BoolNode(cmp, btest));
return generate_fair_guard(bol, region);
Node* ctrl = generate_fair_guard(bol, region);
Node* is_array_ctrl = not_array ? control() : ctrl;
if (obj != nullptr && is_array_ctrl != nullptr && is_array_ctrl != top()) {
// Keep track of the fact that 'obj' is an array to prevent
// array specific accesses from floating above the guard.
Node* cast = _gvn.transform(new CastPPNode(is_array_ctrl, *obj, TypeAryPtr::BOTTOM));
// Check for top because in rare cases, the type system can determine that
// the object can't be an array but the layout helper check is not folded.
if (!cast->is_top()) {
*obj = cast;
}
}
return ctrl;
}
@@ -4399,7 +4411,7 @@ bool LibraryCallKit::inline_native_getLength() {
if (stopped()) return true;
// Deoptimize if it is a non-array.
Node* non_array = generate_non_array_guard(load_object_klass(array), nullptr);
Node* non_array = generate_non_array_guard(load_object_klass(array), nullptr, &array);
if (non_array != nullptr) {
PreserveJVMState pjvms(this);
@@ -5259,12 +5271,13 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
record_for_igvn(result_reg);
Node* obj_klass = load_object_klass(obj);
Node* array_ctl = generate_array_guard(obj_klass, (RegionNode*)nullptr);
Node* array_obj = obj;
Node* array_ctl = generate_array_guard(obj_klass, (RegionNode*)nullptr, &array_obj);
if (array_ctl != nullptr) {
// It's an array.
PreserveJVMState pjvms(this);
set_control(array_ctl);
Node* obj_length = load_array_length(obj);
Node* obj_length = load_array_length(array_obj);
Node* array_size = nullptr; // Size of the array without object alignment padding.
Node* alloc_obj = new_array(obj_klass, obj_length, 0, &array_size, /*deoptimize_on_exception=*/true);
@@ -5278,7 +5291,7 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
set_control(is_obja);
// Generate a direct call to the right arraycopy function(s).
// Clones are always tightly coupled.
ArrayCopyNode* ac = ArrayCopyNode::make(this, true, obj, intcon(0), alloc_obj, intcon(0), obj_length, true, false);
ArrayCopyNode* ac = ArrayCopyNode::make(this, true, array_obj, intcon(0), alloc_obj, intcon(0), obj_length, true, false);
ac->set_clone_oop_array();
Node* n = _gvn.transform(ac);
assert(n == ac, "cannot disappear");
@@ -5299,7 +5312,7 @@ bool LibraryCallKit::inline_native_clone(bool is_virtual) {
// the object.)
if (!stopped()) {
copy_to_clone(obj, alloc_obj, array_size, true);
copy_to_clone(array_obj, alloc_obj, array_size, true);
// Present the results of the copy.
result_reg->init_req(_array_path, control());
@@ -5920,8 +5933,8 @@ bool LibraryCallKit::inline_arraycopy() {
record_for_igvn(slow_region);
// (1) src and dest are arrays.
generate_non_array_guard(load_object_klass(src), slow_region);
generate_non_array_guard(load_object_klass(dest), slow_region);
generate_non_array_guard(load_object_klass(src), slow_region, &src);
generate_non_array_guard(load_object_klass(dest), slow_region, &dest);
// (2) src and dest arrays must have elements of the same BasicType
// done at macro expansion or at Ideal transformation time
@@ -8537,7 +8550,7 @@ bool LibraryCallKit::inline_getObjectSize() {
PhiNode* result_val = new PhiNode(result_reg, TypeLong::LONG);
record_for_igvn(result_reg);
Node* array_ctl = generate_array_guard(klass_node, nullptr);
Node* array_ctl = generate_array_guard(klass_node, nullptr, &obj);
if (array_ctl != nullptr) {
// Array case: size is round(header + element_size*arraylength).
// Since arraylength is different for every array instance, we have to

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@@ -106,6 +106,10 @@ class LibraryCallKit : public GraphKit {
void push_result() {
// Push the result onto the stack.
if (!stopped() && result() != nullptr) {
if (result()->is_top()) {
assert(false, "Can't determine return value.");
C->record_method_not_compilable("Can't determine return value.");
}
BasicType bt = result()->bottom_type()->basic_type();
push_node(bt, result());
}
@@ -163,20 +167,20 @@ class LibraryCallKit : public GraphKit {
RegionNode* region);
Node* generate_interface_guard(Node* kls, RegionNode* region);
Node* generate_hidden_class_guard(Node* kls, RegionNode* region);
Node* generate_array_guard(Node* kls, RegionNode* region) {
return generate_array_guard_common(kls, region, false, false);
Node* generate_array_guard(Node* kls, RegionNode* region, Node** obj = nullptr) {
return generate_array_guard_common(kls, region, false, false, obj);
}
Node* generate_non_array_guard(Node* kls, RegionNode* region) {
return generate_array_guard_common(kls, region, false, true);
Node* generate_non_array_guard(Node* kls, RegionNode* region, Node** obj = nullptr) {
return generate_array_guard_common(kls, region, false, true, obj);
}
Node* generate_objArray_guard(Node* kls, RegionNode* region) {
return generate_array_guard_common(kls, region, true, false);
Node* generate_objArray_guard(Node* kls, RegionNode* region, Node** obj = nullptr) {
return generate_array_guard_common(kls, region, true, false, obj);
}
Node* generate_non_objArray_guard(Node* kls, RegionNode* region) {
return generate_array_guard_common(kls, region, true, true);
Node* generate_non_objArray_guard(Node* kls, RegionNode* region, Node** obj = nullptr) {
return generate_array_guard_common(kls, region, true, true, obj);
}
Node* generate_array_guard_common(Node* kls, RegionNode* region,
bool obj_array, bool not_array);
bool obj_array, bool not_array, Node** obj = nullptr);
Node* generate_virtual_guard(Node* obj_klass, RegionNode* slow_region);
CallJavaNode* generate_method_call(vmIntrinsicID method_id, bool is_virtual, bool is_static, bool res_not_null);
CallJavaNode* generate_method_call_static(vmIntrinsicID method_id, bool res_not_null) {

View File

@@ -1623,27 +1623,17 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) {
return new BoolNode( ncmp, _test.negate() );
}
// Change ((x & (m - 1)) u< m) into (m > 0)
// This is the off-by-one variant of ((x & m) u<= m)
if (cop == Op_CmpU &&
_test._test == BoolTest::lt &&
cmp1_op == Op_AndI) {
Node* l = cmp1->in(1);
Node* r = cmp1->in(2);
for (int repeat = 0; repeat < 2; repeat++) {
bool match = r->Opcode() == Op_AddI && r->in(2)->find_int_con(0) == -1 &&
r->in(1) == cmp2;
if (match) {
// arraylength known to be non-negative, so a (arraylength != 0) is sufficient,
// but to be compatible with the array range check pattern, use (arraylength u> 0)
Node* ncmp = cmp2->Opcode() == Op_LoadRange
? phase->transform(new CmpUNode(cmp2, phase->intcon(0)))
: phase->transform(new CmpINode(cmp2, phase->intcon(0)));
return new BoolNode(ncmp, BoolTest::gt);
} else {
// commute and try again
l = cmp1->in(2);
r = cmp1->in(1);
// Transform: "((x & (m - 1)) <u m)" or "(((m - 1) & x) <u m)" into "(m >u 0)"
// This is case [CMPU_MASK] which is further described at the method comment of BoolNode::Value_cmpu_and_mask().
if (cop == Op_CmpU && _test._test == BoolTest::lt && cmp1_op == Op_AndI) {
Node* m = cmp2; // RHS: m
for (int add_idx = 1; add_idx <= 2; add_idx++) { // LHS: "(m + (-1)) & x" or "x & (m + (-1))"?
Node* maybe_m_minus_1 = cmp1->in(add_idx);
if (maybe_m_minus_1->Opcode() == Op_AddI &&
maybe_m_minus_1->in(2)->find_int_con(0) == -1 &&
maybe_m_minus_1->in(1) == m) {
Node* m_cmpu_0 = phase->transform(new CmpUNode(m, phase->intcon(0)));
return new BoolNode(m_cmpu_0, BoolTest::gt);
}
}
}
@@ -1809,9 +1799,57 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) {
// }
}
//------------------------------Value------------------------------------------
// Change ((x & m) u<= m) or ((m & x) u<= m) to always true
// Same with ((x & m) u< m+1) and ((m & x) u< m+1)
// We use the following Lemmas/insights for the following two transformations (1) and (2):
// x & y <=u y, for any x and y (Lemma 1, masking always results in a smaller unsigned number)
// y <u y + 1 is always true if y != -1 (Lemma 2, (uint)(-1 + 1) == (uint)(UINT_MAX + 1) which overflows)
// y <u 0 is always false for any y (Lemma 3, 0 == UINT_MIN and nothing can be smaller than that)
//
// (1a) Always: Change ((x & m) <=u m ) or ((m & x) <=u m ) to always true (true by Lemma 1)
// (1b) If m != -1: Change ((x & m) <u m + 1) or ((m & x) <u m + 1) to always true:
// x & m <=u m is always true // (Lemma 1)
// x & m <=u m <u m + 1 is always true // (Lemma 2: m <u m + 1, if m != -1)
//
// A counter example for (1b), if we allowed m == -1:
// (x & m) <u m + 1
// (x & -1) <u 0
// x <u 0
// which is false for any x (Lemma 3)
//
// (2) Change ((x & (m - 1)) <u m) or (((m - 1) & x) <u m) to (m >u 0)
// This is the off-by-one variant of the above.
//
// We now prove that this replacement is correct. This is the same as proving
// "m >u 0" if and only if "x & (m - 1) <u m", i.e. "m >u 0 <=> x & (m - 1) <u m"
//
// We use (Lemma 1) and (Lemma 3) from above.
//
// Case "x & (m - 1) <u m => m >u 0":
// We prove this by contradiction:
// Assume m <=u 0 which is equivalent to m == 0:
// and thus
// x & (m - 1) <u m = 0 // m == 0
// y <u 0 // y = x & (m - 1)
// by Lemma 3, this is always false, i.e. a contradiction to our assumption.
//
// Case "m >u 0 => x & (m - 1) <u m":
// x & (m - 1) <=u (m - 1) // (Lemma 1)
// x & (m - 1) <=u (m - 1) <u m // Using assumption m >u 0, no underflow of "m - 1"
//
//
// Note that the signed version of "m > 0":
// m > 0 <=> x & (m - 1) <u m
// does not hold:
// Assume m == -1 and x == -1:
// x & (m - 1) <u m
// -1 & -2 <u -1
// -2 <u -1
// UINT_MAX - 1 <u UINT_MAX // Signed to unsigned numbers
// which is true while
// m > 0
// is false which is a contradiction.
//
// (1a) and (1b) is covered by this method since we can directly return a true value as type while (2) is covered
// in BoolNode::Ideal since we create a new non-constant node (see [CMPU_MASK]).
const Type* BoolNode::Value_cmpu_and_mask(PhaseValues* phase) const {
Node* cmp = in(1);
if (cmp != nullptr && cmp->Opcode() == Op_CmpU) {
@@ -1819,14 +1857,21 @@ const Type* BoolNode::Value_cmpu_and_mask(PhaseValues* phase) const {
Node* cmp2 = cmp->in(2);
if (cmp1->Opcode() == Op_AndI) {
Node* bound = nullptr;
Node* m = nullptr;
if (_test._test == BoolTest::le) {
bound = cmp2;
// (1a) "((x & m) <=u m)", cmp2 = m
m = cmp2;
} else if (_test._test == BoolTest::lt && cmp2->Opcode() == Op_AddI && cmp2->in(2)->find_int_con(0) == 1) {
bound = cmp2->in(1);
// (1b) "(x & m) <u m + 1" and "(m & x) <u m + 1", cmp2 = m + 1
Node* rhs_m = cmp2->in(1);
const TypeInt* rhs_m_type = phase->type(rhs_m)->isa_int();
if (rhs_m_type->_lo > -1 || rhs_m_type->_hi < -1) {
// Exclude any case where m == -1 is possible.
m = rhs_m;
}
}
if (cmp1->in(2) == bound || cmp1->in(1) == bound) {
if (cmp1->in(2) == m || cmp1->in(1) == m) {
return TypeInt::ONE;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@@ -582,6 +582,7 @@ void Type::Initialize_shared(Compile* current) {
TypeAryPtr::_array_interfaces = TypeInterfaces::make(&array_interfaces);
TypeAryKlassPtr::_array_interfaces = TypeAryPtr::_array_interfaces;
TypeAryPtr::BOTTOM = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(Type::BOTTOM, TypeInt::POS), nullptr, false, Type::OffsetBot);
TypeAryPtr::RANGE = TypeAryPtr::make( TypePtr::BotPTR, TypeAry::make(Type::BOTTOM,TypeInt::POS), nullptr /* current->env()->Object_klass() */, false, arrayOopDesc::length_offset_in_bytes());
TypeAryPtr::NARROWOOPS = TypeAryPtr::make(TypePtr::BotPTR, TypeAry::make(TypeNarrowOop::BOTTOM, TypeInt::POS), nullptr /*ciArrayKlass::make(o)*/, false, Type::OffsetBot);
@@ -4682,16 +4683,17 @@ bool TypeAryKlassPtr::is_meet_subtype_of_helper(const TypeKlassPtr *other, bool
//=============================================================================
// Convenience common pre-built types.
const TypeAryPtr *TypeAryPtr::RANGE;
const TypeAryPtr *TypeAryPtr::OOPS;
const TypeAryPtr *TypeAryPtr::NARROWOOPS;
const TypeAryPtr *TypeAryPtr::BYTES;
const TypeAryPtr *TypeAryPtr::SHORTS;
const TypeAryPtr *TypeAryPtr::CHARS;
const TypeAryPtr *TypeAryPtr::INTS;
const TypeAryPtr *TypeAryPtr::LONGS;
const TypeAryPtr *TypeAryPtr::FLOATS;
const TypeAryPtr *TypeAryPtr::DOUBLES;
const TypeAryPtr* TypeAryPtr::BOTTOM;
const TypeAryPtr* TypeAryPtr::RANGE;
const TypeAryPtr* TypeAryPtr::OOPS;
const TypeAryPtr* TypeAryPtr::NARROWOOPS;
const TypeAryPtr* TypeAryPtr::BYTES;
const TypeAryPtr* TypeAryPtr::SHORTS;
const TypeAryPtr* TypeAryPtr::CHARS;
const TypeAryPtr* TypeAryPtr::INTS;
const TypeAryPtr* TypeAryPtr::LONGS;
const TypeAryPtr* TypeAryPtr::FLOATS;
const TypeAryPtr* TypeAryPtr::DOUBLES;
//------------------------------make-------------------------------------------
const TypeAryPtr *TypeAryPtr::make(PTR ptr, const TypeAry *ary, ciKlass* k, bool xk, int offset,

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@@ -1470,16 +1470,17 @@ public:
virtual const TypeKlassPtr* as_klass_type(bool try_for_exact = false) const;
// Convenience common pre-built types.
static const TypeAryPtr *RANGE;
static const TypeAryPtr *OOPS;
static const TypeAryPtr *NARROWOOPS;
static const TypeAryPtr *BYTES;
static const TypeAryPtr *SHORTS;
static const TypeAryPtr *CHARS;
static const TypeAryPtr *INTS;
static const TypeAryPtr *LONGS;
static const TypeAryPtr *FLOATS;
static const TypeAryPtr *DOUBLES;
static const TypeAryPtr* BOTTOM;
static const TypeAryPtr* RANGE;
static const TypeAryPtr* OOPS;
static const TypeAryPtr* NARROWOOPS;
static const TypeAryPtr* BYTES;
static const TypeAryPtr* SHORTS;
static const TypeAryPtr* CHARS;
static const TypeAryPtr* INTS;
static const TypeAryPtr* LONGS;
static const TypeAryPtr* FLOATS;
static const TypeAryPtr* DOUBLES;
// selects one of the above:
static const TypeAryPtr *get_array_body_type(BasicType elem) {
assert((uint)elem <= T_CONFLICT && _array_body_type[elem] != nullptr, "bad elem type");

View File

@@ -1637,8 +1637,9 @@ bool LibraryCallKit::inline_vector_reduction() {
int opc = VectorSupport::vop2ideal(opr->get_con(), elem_bt);
int sopc = ReductionNode::opcode(opc, elem_bt);
// Ensure reduction operation for lanewise operation
// When using mask, mask use type needs to be VecMaskUseLoad.
if (!arch_supports_vector(sopc, num_elem, elem_bt, is_masked_op ? VecMaskUseLoad : VecMaskNotUsed)) {
if (sopc == opc || !arch_supports_vector(sopc, num_elem, elem_bt, is_masked_op ? VecMaskUseLoad : VecMaskNotUsed)) {
log_if_needed(" ** not supported: arity=1 op=%d/reduce vlen=%d etype=%s is_masked_op=%d",
sopc, num_elem, type2name(elem_bt), is_masked_op ? 1 : 0);
return false;

View File

@@ -1466,6 +1466,9 @@ bool VectorCastNode::implemented(int opc, uint vlen, BasicType src_type, BasicTy
if (is_java_primitive(dst_type) &&
is_java_primitive(src_type) &&
(vlen > 1) && is_power_of_2(vlen) &&
// In rare case, the input to the VectorCast could be a Replicate node. We need to make sure creating is supported:
// check the src_type:
VectorNode::vector_size_supported_auto_vectorization(src_type, vlen) &&
VectorNode::vector_size_supported_auto_vectorization(dst_type, vlen)) {
int vopc = VectorCastNode::opcode(opc, src_type);
return vopc > 0 && Matcher::match_rule_supported_auto_vectorization(vopc, vlen, dst_type);

View File

@@ -598,7 +598,7 @@ JvmtiEventControllerPrivate::recompute_thread_enabled(JvmtiThreadState *state) {
}
// compute interp_only mode
bool should_be_interp = (any_env_enabled & INTERP_EVENT_BITS) != 0 || has_frame_pops;
bool is_now_interp = state->is_interp_only_mode();
bool is_now_interp = state->is_interp_only_mode() || state->is_pending_interp_only_mode();
if (should_be_interp != is_now_interp) {
if (should_be_interp) {

View File

@@ -103,6 +103,7 @@ bool Arguments::_ClipInlining = ClipInlining;
size_t Arguments::_default_SharedBaseAddress = SharedBaseAddress;
bool Arguments::_enable_preview = false;
bool Arguments::_has_jdwp_agent = false;
LegacyGCLogging Arguments::_legacyGCLogging = { nullptr, 0 };
@@ -2021,7 +2022,7 @@ jint Arguments::parse_vm_init_args(const JavaVMInitArgs *vm_options_args,
return JNI_OK;
}
#if !INCLUDE_JVMTI
#if !INCLUDE_JVMTI || INCLUDE_CDS
// Checks if name in command-line argument -agent{lib,path}:name[=options]
// represents a valid JDWP agent. is_path==true denotes that we
// are dealing with -agentpath (case where name is a path), otherwise with
@@ -2319,6 +2320,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin
"Debugging agents are not supported in this VM\n");
return JNI_ERR;
}
#elif INCLUDE_CDS
if (valid_jdwp_agent(name, is_absolute_path)) {
_has_jdwp_agent = true;
}
#endif // !INCLUDE_JVMTI
JvmtiAgentList::add(name, options, is_absolute_path);
os::free(name);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 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
@@ -254,6 +254,9 @@ class Arguments : AllStatic {
// preview features
static bool _enable_preview;
// jdwp
static bool _has_jdwp_agent;
// Used to save default settings
static bool _AlwaysCompileLoopMethods;
static bool _UseOnStackReplacement;
@@ -506,6 +509,9 @@ class Arguments : AllStatic {
static void set_enable_preview() { _enable_preview = true; }
static bool enable_preview() { return _enable_preview; }
// jdwp
static bool has_jdwp_agent() { return _has_jdwp_agent; }
// Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid.
static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen);

View File

@@ -60,14 +60,14 @@ JVM_END
#if INCLUDE_JVMTI
class JvmtiUnmountBeginMark : public StackObj {
Handle _vthread;
JavaThread* _target;
JavaThread* _current;
freeze_result _result;
bool _failed;
public:
JvmtiUnmountBeginMark(JavaThread* t) :
_vthread(t, t->vthread()), _target(t), _result(freeze_pinned_native), _failed(false) {
assert(!_target->is_in_VTMS_transition(), "must be");
_vthread(t, t->vthread()), _current(t), _result(freeze_pinned_native), _failed(false) {
assert(!_current->is_in_VTMS_transition(), "must be");
if (JvmtiVTMSTransitionDisabler::VTMS_notify_jvmti_events()) {
JvmtiVTMSTransitionDisabler::VTMS_vthread_unmount((jthread)_vthread.raw_value(), true);
@@ -75,26 +75,26 @@ class JvmtiUnmountBeginMark : public StackObj {
// Don't preempt if there is a pending popframe or earlyret operation. This can
// be installed in start_VTMS_transition() so we need to check it here.
if (JvmtiExport::can_pop_frame() || JvmtiExport::can_force_early_return()) {
JvmtiThreadState* state = _target->jvmti_thread_state();
if (_target->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) {
JvmtiThreadState* state = _current->jvmti_thread_state();
if (_current->has_pending_popframe() || (state != nullptr && state->is_earlyret_pending())) {
_failed = true;
}
}
// Don't preempt in case there is an async exception installed since
// we would incorrectly throw it during the unmount logic in the carrier.
if (_target->has_async_exception_condition()) {
if (_current->has_async_exception_condition()) {
_failed = true;
}
} else {
_target->set_is_in_VTMS_transition(true);
_current->set_is_in_VTMS_transition(true);
java_lang_Thread::set_is_in_VTMS_transition(_vthread(), true);
}
}
~JvmtiUnmountBeginMark() {
assert(!_target->is_suspended(), "must be");
assert(!_current->is_suspended(), "must be");
assert(_target->is_in_VTMS_transition(), "must be");
assert(_current->is_in_VTMS_transition(), "must be");
assert(java_lang_Thread::is_in_VTMS_transition(_vthread()), "must be");
// Read it again since for late binding agents the flag could have
@@ -106,7 +106,7 @@ class JvmtiUnmountBeginMark : public StackObj {
if (jvmti_present) {
JvmtiVTMSTransitionDisabler::VTMS_vthread_mount((jthread)_vthread.raw_value(), false);
} else {
_target->set_is_in_VTMS_transition(false);
_current->set_is_in_VTMS_transition(false);
java_lang_Thread::set_is_in_VTMS_transition(_vthread(), false);
}
}
@@ -115,51 +115,59 @@ class JvmtiUnmountBeginMark : public StackObj {
bool failed() { return _failed; }
};
static bool is_vthread_safe_to_preempt_for_jvmti(JavaThread* target) {
if (target->is_in_VTMS_transition()) {
// We caught target at the end of a mount transition.
static bool is_vthread_safe_to_preempt_for_jvmti(JavaThread* current) {
if (current->is_in_VTMS_transition()) {
// We are at the end of a mount transition.
return false;
}
return true;
}
#endif // INCLUDE_JVMTI
static bool is_vthread_safe_to_preempt(JavaThread* target, oop vthread) {
static bool is_vthread_safe_to_preempt(JavaThread* current, oop vthread) {
assert(java_lang_VirtualThread::is_instance(vthread), "");
if (java_lang_VirtualThread::state(vthread) != java_lang_VirtualThread::RUNNING) { // inside transition
return false;
}
return JVMTI_ONLY(is_vthread_safe_to_preempt_for_jvmti(target)) NOT_JVMTI(true);
return JVMTI_ONLY(is_vthread_safe_to_preempt_for_jvmti(current)) NOT_JVMTI(true);
}
typedef freeze_result (*FreezeContFnT)(JavaThread*, intptr_t*);
static void verify_preempt_preconditions(JavaThread* target, oop continuation) {
assert(target == JavaThread::current(), "no support for external preemption");
assert(target->has_last_Java_frame(), "");
assert(!target->preempting(), "");
assert(target->last_continuation() != nullptr, "");
assert(target->last_continuation()->cont_oop(target) == continuation, "");
static void verify_preempt_preconditions(JavaThread* current, oop continuation) {
assert(current == JavaThread::current(), "no support for external preemption");
assert(current->has_last_Java_frame(), "");
assert(!current->preempting(), "");
assert(current->last_continuation() != nullptr, "");
assert(current->last_continuation()->cont_oop(current) == continuation, "");
assert(Continuation::continuation_scope(continuation) == java_lang_VirtualThread::vthread_scope(), "");
assert(!target->has_pending_exception(), "");
assert(!current->has_pending_exception(), "");
}
freeze_result Continuation::try_preempt(JavaThread* target, oop continuation) {
verify_preempt_preconditions(target, continuation);
freeze_result Continuation::try_preempt(JavaThread* current, oop continuation) {
verify_preempt_preconditions(current, continuation);
if (LockingMode == LM_LEGACY) {
return freeze_unsupported;
}
if (!is_vthread_safe_to_preempt(target, target->vthread())) {
if (!is_vthread_safe_to_preempt(current, current->vthread())) {
return freeze_pinned_native;
}
JVMTI_ONLY(JvmtiUnmountBeginMark jubm(target);)
JVMTI_ONLY(JvmtiUnmountBeginMark jubm(current);)
JVMTI_ONLY(if (jubm.failed()) return freeze_pinned_native;)
freeze_result res = CAST_TO_FN_PTR(FreezeContFnT, freeze_preempt_entry())(target, target->last_Java_sp());
freeze_result res = CAST_TO_FN_PTR(FreezeContFnT, freeze_preempt_entry())(current, current->last_Java_sp());
log_trace(continuations, preempt)("try_preempt: %d", res);
JVMTI_ONLY(jubm.set_result(res);)
if (current->has_pending_exception()) {
assert(res == freeze_exception, "expecting an exception result from freeze");
// We don't want to throw exceptions, especially when returning
// from monitorenter since the compiler does not expect one. We
// just ignore the exception and pin the vthread to the carrier.
current->clear_pending_exception();
}
return res;
}

View File

@@ -2603,6 +2603,7 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n
|| (stub_caller && f.cb()->as_nmethod()->is_marked_for_deoptimization())) {
// The caller of the safepoint stub when the continuation is preempted is not at a call instruction, and so
// cannot rely on nmethod patching for deopt.
assert(_thread->is_interp_only_mode() || stub_caller, "expected a stub-caller");
log_develop_trace(continuations)("Deoptimizing thawed frame");
DEBUG_ONLY(ContinuationHelper::Frame::patch_pc(f, nullptr));

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1998, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 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
@@ -1264,36 +1264,49 @@ static bool monitors_used_above_threshold(MonitorList* list) {
if (MonitorUsedDeflationThreshold == 0) { // disabled case is easy
return false;
}
// Start with ceiling based on a per-thread estimate:
size_t ceiling = ObjectSynchronizer::in_use_list_ceiling();
size_t old_ceiling = ceiling;
if (ceiling < list->max()) {
// The max used by the system has exceeded the ceiling so use that:
ceiling = list->max();
}
size_t monitors_used = list->count();
if (monitors_used == 0) { // empty list is easy
return false;
}
if (NoAsyncDeflationProgressMax != 0 &&
_no_progress_cnt >= NoAsyncDeflationProgressMax) {
double remainder = (100.0 - MonitorUsedDeflationThreshold) / 100.0;
size_t new_ceiling = ceiling + (size_t)((double)ceiling * remainder) + 1;
ObjectSynchronizer::set_in_use_list_ceiling(new_ceiling);
log_info(monitorinflation)("Too many deflations without progress; "
"bumping in_use_list_ceiling from " SIZE_FORMAT
" to " SIZE_FORMAT, old_ceiling, new_ceiling);
_no_progress_cnt = 0;
ceiling = new_ceiling;
}
size_t old_ceiling = ObjectSynchronizer::in_use_list_ceiling();
// Make sure that we use a ceiling value that is not lower than
// previous, not lower than the recorded max used by the system, and
// not lower than the current number of monitors in use (which can
// race ahead of max). The result is guaranteed > 0.
size_t ceiling = MAX3(old_ceiling, list->max(), monitors_used);
// Check if our monitor usage is above the threshold:
size_t monitor_usage = (monitors_used * 100LL) / ceiling;
if (int(monitor_usage) > MonitorUsedDeflationThreshold) {
// Deflate monitors if over the threshold percentage, unless no
// progress on previous deflations.
bool is_above_threshold = true;
// Check if it's time to adjust the in_use_list_ceiling up, due
// to too many async deflation attempts without any progress.
if (NoAsyncDeflationProgressMax != 0 &&
_no_progress_cnt >= NoAsyncDeflationProgressMax) {
double remainder = (100.0 - MonitorUsedDeflationThreshold) / 100.0;
size_t delta = (size_t)(ceiling * remainder) + 1;
size_t new_ceiling = (ceiling > SIZE_MAX - delta)
? SIZE_MAX // Overflow, let's clamp new_ceiling.
: ceiling + delta;
ObjectSynchronizer::set_in_use_list_ceiling(new_ceiling);
log_info(monitorinflation)("Too many deflations without progress; "
"bumping in_use_list_ceiling from " SIZE_FORMAT
" to " SIZE_FORMAT, old_ceiling, new_ceiling);
_no_progress_cnt = 0;
ceiling = new_ceiling;
// Check if our monitor usage is still above the threshold:
monitor_usage = (monitors_used * 100LL) / ceiling;
is_above_threshold = int(monitor_usage) > MonitorUsedDeflationThreshold;
}
log_info(monitorinflation)("monitors_used=" SIZE_FORMAT ", ceiling=" SIZE_FORMAT
", monitor_usage=" SIZE_FORMAT ", threshold=%d",
monitors_used, ceiling, monitor_usage, MonitorUsedDeflationThreshold);
return true;
return is_above_threshold;
}
return false;

View File

@@ -2349,11 +2349,10 @@ void VM_HeapDumper::dump_threads(AbstractDumpWriter* writer) {
}
bool VM_HeapDumper::doit_prologue() {
if (_gc_before_heap_dump && UseZGC) {
// ZGC cannot perform a synchronous GC cycle from within the VM thread.
// So ZCollectedHeap::collect_as_vm_thread() is a noop. To respect the
// _gc_before_heap_dump flag a synchronous GC cycle is performed from
// the caller thread in the prologue.
if (_gc_before_heap_dump && (UseZGC || UseShenandoahGC)) {
// ZGC and Shenandoah cannot perform a synchronous GC cycle from within the VM thread.
// So collect_as_vm_thread() is a noop. To respect the _gc_before_heap_dump flag a
// synchronous GC cycle is performed from the caller thread in the prologue.
Universe::heap()->collect(GCCause::_heap_dump);
}
return VM_GC_Operation::doit_prologue();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* 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
@@ -180,8 +180,8 @@ abstract class HKDFKeyDerivation extends KDFSpi {
} else if (derivationSpec instanceof HKDFParameterSpec.Expand anExpand) {
// set this value in the "if"
if ((pseudoRandomKey = anExpand.prk().getEncoded()) == null) {
throw new AssertionError(
"PRK is required for HKDFParameterSpec.Expand");
throw new InvalidAlgorithmParameterException(
"Cannot retrieve PRK for HKDFParameterSpec.Expand");
}
// set this value in the "if"
if ((info = anExpand.info()) == null) {
@@ -411,4 +411,4 @@ abstract class HKDFKeyDerivation extends KDFSpi {
}
}
}
}

View File

@@ -640,11 +640,14 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
int count = this.count;
byte[] val = this.value;
if (isLatin1()) {
StringLatin1.putCharsAt(val, count, 'n', 'u', 'l', 'l');
val[count++] = 'n';
val[count++] = 'u';
val[count++] = 'l';
val[count++] = 'l';
} else {
StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l');
count = StringUTF16.putCharsAt(val, count, 'n', 'u', 'l', 'l');
}
this.count = count + 4;
this.count = count;
return this;
}
@@ -769,18 +772,25 @@ abstract sealed class AbstractStringBuilder implements Appendable, CharSequence
byte[] val = this.value;
if (isLatin1()) {
if (b) {
StringLatin1.putCharsAt(val, count, 't', 'r', 'u', 'e');
val[count++] = 't';
val[count++] = 'r';
val[count++] = 'u';
val[count++] = 'e';
} else {
StringLatin1.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e');
val[count++] = 'f';
val[count++] = 'a';
val[count++] = 'l';
val[count++] = 's';
val[count++] = 'e';
}
} else {
if (b) {
StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e');
count = StringUTF16.putCharsAt(val, count, 't', 'r', 'u', 'e');
} else {
StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e');
count = StringUTF16.putCharsAt(val, count, 'f', 'a', 'l', 's', 'e');
}
}
this.count = count + (b ? 4 : 5);
this.count = count;
return this;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 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
@@ -349,8 +349,8 @@ import jdk.internal.vm.annotation.IntrinsicCandidate;
* @jls 15.21.1 Numerical Equality Operators == and !=
* @jls 15.20.1 Numerical Comparison Operators {@code <}, {@code <=}, {@code >}, and {@code >=}
*
* @see <a href="https://standards.ieee.org/ieee/754/6210/">
* <cite>IEEE Standard for Floating-Point Arithmetic</cite></a>
* @spec https://standards.ieee.org/ieee/754/6210/
* IEEE Standard for Floating-Point Arithmetic
*
* @author Lee Boynton
* @author Arthur van Hoff

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 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
@@ -67,8 +67,8 @@ import jdk.internal.vm.annotation.IntrinsicCandidate;
* decimal conversion issues} in {@code java.lang.Double} is also
* applicable to {@code float} values.
*
* @see <a href="https://standards.ieee.org/ieee/754/6210/">
* <cite>IEEE Standard for Floating-Point Arithmetic</cite></a>
* @spec https://standards.ieee.org/ieee/754/6210/
* IEEE Standard for Floating-Point Arithmetic
*
* @author Lee Boynton
* @author Arthur van Hoff

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1994, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1994, 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
@@ -120,8 +120,8 @@ import static java.lang.Double.*;
* implementation condition than required for most of the methods in
* question that are also included in this class.
*
* @see <a href="https://standards.ieee.org/ieee/754/6210/">
* <cite>IEEE Standard for Floating-Point Arithmetic</cite></a>
* @spec https://standards.ieee.org/ieee/754/6210/
* IEEE Standard for Floating-Point Arithmetic
*
* @since 1.0
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 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
@@ -98,8 +98,8 @@ import jdk.internal.vm.annotation.IntrinsicCandidate;
* href="Math.html#Ieee754RecommendedOps">relate to the IEEE 754
* recommended operations</a>.
*
* @see <a href="https://standards.ieee.org/ieee/754/6210/">
* <cite>IEEE Standard for Floating-Point Arithmetic</cite></a>
* @spec https://standards.ieee.org/ieee/754/6210/
* IEEE Standard for Floating-Point Arithmetic
*
* @author Joseph D. Darcy
* @since 1.3

View File

@@ -236,10 +236,17 @@ final class StringConcatHelper {
if (indexCoder < UTF16) {
if (value) {
index -= 4;
StringLatin1.putCharsAt(buf, index, 't', 'r', 'u', 'e');
buf[index] = 't';
buf[index + 1] = 'r';
buf[index + 2] = 'u';
buf[index + 3] = 'e';
} else {
index -= 5;
StringLatin1.putCharsAt(buf, index, 'f', 'a', 'l', 's', 'e');
buf[index] = 'f';
buf[index + 1] = 'a';
buf[index + 2] = 'l';
buf[index + 3] = 's';
buf[index + 4] = 'e';
}
index -= prefix.length();
prefix.getBytes(buf, index, String.LATIN1);
@@ -247,10 +254,17 @@ final class StringConcatHelper {
} else {
if (value) {
index -= 4;
StringUTF16.putCharsAt(buf, index, 't', 'r', 'u', 'e');
StringUTF16.putChar(buf, index, 't');
StringUTF16.putChar(buf, index + 1, 'r');
StringUTF16.putChar(buf, index + 2, 'u');
StringUTF16.putChar(buf, index + 3, 'e');
} else {
index -= 5;
StringUTF16.putCharsAt(buf, index, 'f', 'a', 'l', 's', 'e');
StringUTF16.putChar(buf, index, 'f');
StringUTF16.putChar(buf, index + 1, 'a');
StringUTF16.putChar(buf, index + 2, 'l');
StringUTF16.putChar(buf, index + 3, 's');
StringUTF16.putChar(buf, index + 4, 'e');
}
index -= prefix.length();
prefix.getBytes(buf, index, String.UTF16);
@@ -624,20 +638,34 @@ final class StringConcatHelper {
if (coder == String.LATIN1) {
if (value) {
index -= 4;
StringLatin1.putCharsAt(buf, index, 't', 'r', 'u', 'e');
buf[index] = 't';
buf[index + 1] = 'r';
buf[index + 2] = 'u';
buf[index + 3] = 'e';
} else {
index -= 5;
StringLatin1.putCharsAt(buf, index, 'f', 'a', 'l', 's', 'e');
buf[index] = 'f';
buf[index + 1] = 'a';
buf[index + 2] = 'l';
buf[index + 3] = 's';
buf[index + 4] = 'e';
}
index -= prefix.length();
prefix.getBytes(buf, index, String.LATIN1);
} else {
if (value) {
index -= 4;
StringUTF16.putCharsAt(buf, index, 't', 'r', 'u', 'e');
StringUTF16.putChar(buf, index, 't');
StringUTF16.putChar(buf, index + 1, 'r');
StringUTF16.putChar(buf, index + 2, 'u');
StringUTF16.putChar(buf, index + 3, 'e');
} else {
index -= 5;
StringUTF16.putCharsAt(buf, index, 'f', 'a', 'l', 's', 'e');
StringUTF16.putChar(buf, index, 'f');
StringUTF16.putChar(buf, index + 1, 'a');
StringUTF16.putChar(buf, index + 2, 'l');
StringUTF16.putChar(buf, index + 3, 's');
StringUTF16.putChar(buf, index + 4, 'e');
}
index -= prefix.length();
prefix.getBytes(buf, index, String.UTF16);

View File

@@ -32,7 +32,6 @@ import java.util.function.Consumer;
import java.util.function.IntConsumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.misc.Unsafe;
import jdk.internal.util.ArraysSupport;
import jdk.internal.util.DecimalDigits;
import jdk.internal.vm.annotation.IntrinsicCandidate;
@@ -43,8 +42,6 @@ import static java.lang.String.checkIndex;
import static java.lang.String.checkOffset;
final class StringLatin1 {
private static final Unsafe UNSAFE = Unsafe.getUnsafe();
public static char charAt(byte[] value, int index) {
checkIndex(index, value.length);
return (char)(value[index] & 0xff);
@@ -827,27 +824,6 @@ final class StringLatin1 {
return StreamSupport.stream(LinesSpliterator.spliterator(value), false);
}
static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) {
assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check";
// Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores.
long offset = (long) Unsafe.ARRAY_BYTE_BASE_OFFSET + index;
UNSAFE.putByte(val, offset , (byte)(c1));
UNSAFE.putByte(val, offset + 1, (byte)(c2));
UNSAFE.putByte(val, offset + 2, (byte)(c3));
UNSAFE.putByte(val, offset + 3, (byte)(c4));
}
static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) {
assert index >= 0 && index + 4 < length(val) : "Trusted caller missed bounds check";
// Don't use the putChar method, Its instrinsic will cause C2 unable to combining values into larger stores.
long offset = (long) Unsafe.ARRAY_BYTE_BASE_OFFSET + index;
UNSAFE.putByte(val, offset , (byte)(c1));
UNSAFE.putByte(val, offset + 1, (byte)(c2));
UNSAFE.putByte(val, offset + 2, (byte)(c3));
UNSAFE.putByte(val, offset + 3, (byte)(c4));
UNSAFE.putByte(val, offset + 4, (byte)(c5));
}
public static void putChar(byte[] val, int index, int c) {
//assert (canEncode(c));
val[index] = (byte)(c);

View File

@@ -43,6 +43,7 @@ import static java.lang.String.UTF16;
import static java.lang.String.LATIN1;
final class StringUTF16 {
// Return a new byte array for a UTF16-coded string for len chars
// Throw an exception if out of range
public static byte[] newBytesFor(int len) {
@@ -1547,20 +1548,27 @@ final class StringUTF16 {
return true;
}
static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4) {
assert index >= 0 && index + 3 < length(val) : "Trusted caller missed bounds check";
putChar(val, index , c1);
putChar(val, index + 1, c2);
putChar(val, index + 2, c3);
putChar(val, index + 3, c4);
public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4) {
int end = i + 4;
checkBoundsBeginEnd(i, end, value);
putChar(value, i++, c1);
putChar(value, i++, c2);
putChar(value, i++, c3);
putChar(value, i++, c4);
assert(i == end);
return end;
}
static void putCharsAt(byte[] val, int index, int c1, int c2, int c3, int c4, int c5) {
putChar(val, index , c1);
putChar(val, index + 1, c2);
putChar(val, index + 2, c3);
putChar(val, index + 3, c4);
putChar(val, index + 4, c5);
public static int putCharsAt(byte[] value, int i, char c1, char c2, char c3, char c4, char c5) {
int end = i + 5;
checkBoundsBeginEnd(i, end, value);
putChar(value, i++, c1);
putChar(value, i++, c2);
putChar(value, i++, c3);
putChar(value, i++, c4);
putChar(value, i++, c5);
assert(i == end);
return end;
}
public static char charAt(byte[] value, int index) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,10 +30,33 @@ import java.util.Set;
import jdk.internal.classfile.impl.AccessFlagsImpl;
/**
* Models the access flags for a class, method, or field. Delivered as a
* {@link ClassElement}, {@link FieldElement}, or {@link MethodElement}
* when traversing the corresponding model type.
* Models the access flags for a class, method, or field. The access flags
* appears exactly once in each class, method, or field; a {@link
* ClassBuilder} and a {@link FieldBuilder} chooses an unspecified default value
* if access flags are not provided, and a {@link MethodBuilder} is always
* created with access flags.
* <p>
* {@code AccessFlags} cannot be created via a factory method directly; it can
* be created with {@code withFlags} methods on the respective builders.
* <p>
* A {@link MethodBuilder} throws an {@link IllegalArgumentException} if it is
* supplied an {@code AccessFlags} object that changes the preexisting
* {@link ClassFile#ACC_STATIC ACC_STATIC} flag of the builder, because the
* access flag change may invalidate previously supplied data to the builder.
*
* @apiNote
* The access flags of classes, methods, and fields are modeled as a standalone
* object to support streaming as elements for {@link ClassFileTransform}.
* Other access flags are not elements of a {@link CompoundElement} and thus not
* modeled by {@code AccessFlags}; they provide their own {@code flagsMask},
* {@code flags}, and {@code has} methods.
*
* @see ClassModel#flags()
* @see FieldModel#flags()
* @see MethodModel#flags()
* @see ClassBuilder#withFlags
* @see FieldBuilder#withFlags
* @see MethodBuilder#withFlags
* @since 24
*/
public sealed interface AccessFlags
@@ -41,26 +64,36 @@ public sealed interface AccessFlags
permits AccessFlagsImpl {
/**
* {@return the access flags, as a bit mask}
* {@return the access flags, as a bit mask} It is in the range of unsigned
* short, {@code [0, 0xFFFF]}.
*/
int flagsMask();
/**
* {@return the access flags}
* {@return the access flags, as a set of flag enums}
*
* @throws IllegalArgumentException if the flags mask has any undefined bit set
* @see #location()
*/
Set<AccessFlag> flags();
/**
* {@return whether the specified flag is present} The specified flag
* should be a valid flag for the classfile location associated with this
* element otherwise false is returned.
* {@return whether the specified flag is set} If the specified flag
* is not available to this {@linkplain #location() location}, returns
* {@code false}.
*
* @param flag the flag to test
* @see #location()
*/
boolean has(AccessFlag flag);
/**
* {@return the classfile location for this element, which is either class,
* method, or field}
* {@return the {@code class} file location for this element, which is
* either class, method, or field}
*
* @see AccessFlag.Location#CLASS
* @see AccessFlag.Location#FIELD
* @see AccessFlag.Location#METHOD
*/
AccessFlag.Location location();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -41,8 +41,9 @@ import jdk.internal.classfile.impl.Util;
* type_annotation} structure (JVMS {@jvms 4.7.20}). This model indicates the
* interface of the annotation and a set of element-value pairs.
* <p>
* This model can reconstruct an annotation, given the location of the modeled structure
* in the class file and the definition of the annotation interface.
* This model can reconstruct an annotation, given the location of the modeled
* structure in the {@code class} file and the definition of the annotation
* interface.
* <p>
* Two {@code Annotation} objects should be compared using the {@link
* Object#equals(Object) equals} method.
@@ -54,8 +55,8 @@ import jdk.internal.classfile.impl.Util;
* elements with default values (JLS {@jls 9.6.2}), and whether the reconstructed annotation
* is a container annotation for multiple annotations (JLS {@jls 9.7.5}).
*
* @see AnnotationElement
* @see AnnotationValue
* @see java.lang.annotation.Annotation
* @see java.lang.reflect.AnnotatedElement Annotations in core reflection
* @see TypeAnnotation
* @see RuntimeVisibleAnnotationsAttribute
* @see RuntimeInvisibleAnnotationsAttribute
@@ -70,11 +71,15 @@ public sealed interface Annotation
/**
* {@return the constant pool entry holding the {@linkplain Class#descriptorString
* descriptor string} of the annotation interface}
*
* @see java.lang.annotation.Annotation#annotationType()
*/
Utf8Entry className();
/**
* {@return the annotation interface, as a symbolic descriptor}
*
* @see java.lang.annotation.Annotation#annotationType()
*/
default ClassDesc classSymbol() {
return Util.fieldTypeSymbol(className());

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -40,8 +40,8 @@ import jdk.internal.classfile.impl.TemporaryConstantPool;
* {@link Object#equals(Object) equals} method.
*
* @see Annotation
* @see AnnotationValue
*
* @see java.lang.reflect.AnnotatedElement Annotations in core reflection
* @jvms 4.7.16.1 The {@code element_value} structure
* @since 24
*/
public sealed interface AnnotationElement

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -45,6 +45,7 @@ import static java.util.Objects.requireNonNull;
*
* @see Annotation
* @see AnnotationElement
* @see java.lang.reflect.AnnotatedElement Annotations in core reflection
*
* @sealedGraph
* @since 24
@@ -53,7 +54,7 @@ public sealed interface AnnotationValue {
/**
* Models an annotation value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_ANNOTATION}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_ANNOTATION}.
*
* @since 24
*/
@@ -65,7 +66,7 @@ public sealed interface AnnotationValue {
/**
* Models an array value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_ARRAY}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_ARRAY}.
*
* @since 24
*/
@@ -121,7 +122,7 @@ public sealed interface AnnotationValue {
/**
* Models a string value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_STRING}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_STRING}.
*
* @since 24
*/
@@ -148,7 +149,7 @@ public sealed interface AnnotationValue {
/**
* Models a double value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_DOUBLE}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_DOUBLE}.
*
* @since 24
*/
@@ -175,7 +176,7 @@ public sealed interface AnnotationValue {
/**
* Models a float value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_FLOAT}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_FLOAT}.
*
* @since 24
*/
@@ -202,7 +203,7 @@ public sealed interface AnnotationValue {
/**
* Models a long value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_LONG}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_LONG}.
*
* @since 24
*/
@@ -229,7 +230,7 @@ public sealed interface AnnotationValue {
/**
* Models an int value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_INT}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_INT}.
*
* @since 24
*/
@@ -256,7 +257,7 @@ public sealed interface AnnotationValue {
/**
* Models a short value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_SHORT}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_SHORT}.
*
* @since 24
*/
@@ -286,7 +287,7 @@ public sealed interface AnnotationValue {
/**
* Models a char value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_CHAR}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_CHAR}.
*
* @since 24
*/
@@ -316,7 +317,7 @@ public sealed interface AnnotationValue {
/**
* Models a byte value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_BYTE}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_BYTE}.
*
* @since 24
*/
@@ -346,7 +347,7 @@ public sealed interface AnnotationValue {
/**
* Models a boolean value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_BOOLEAN}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_BOOLEAN}.
*
* @since 24
*/
@@ -376,7 +377,7 @@ public sealed interface AnnotationValue {
/**
* Models a class value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_CLASS}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_CLASS}.
*
* @since 24
*/
@@ -393,7 +394,7 @@ public sealed interface AnnotationValue {
/**
* Models an enum value of an element-value pair.
* The {@linkplain #tag tag} of this value is {@value TAG_ENUM}.
* The {@linkplain #tag tag} of this value is {@value %c TAG_ENUM}.
*
* @since 24
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -31,15 +31,31 @@ import jdk.internal.classfile.impl.BoundAttribute;
import jdk.internal.classfile.impl.UnboundAttribute;
/**
* Models a classfile attribute (JVMS {@jvms 4.7}). Many, though not all, subtypes of
* {@linkplain Attribute} will implement {@link ClassElement}, {@link
* MethodElement}, {@link FieldElement}, or {@link CodeElement}; attributes that
* are also elements will be delivered when traversing the elements of the
* corresponding model type. Additionally, all attributes are accessible
* directly from the corresponding model type through {@link
* AttributedElement#findAttribute(AttributeMapper)}.
* @param <A> the attribute type
* Models an attribute (JVMS {@jvms 4.7}) in the {@code class} file format.
* Attributes exist on certain {@code class} file structures modeled by {@link
* AttributedElement}, which provides basic read access to the attributes.
* <p>
* This sealed interface hierarchy includes attributes predefined in the JVMS
* and JDK-specific nonstandard attributes. Their {@linkplain #attributeMapper()
* mappers} are available in {@link Attributes}. Two special subtypes of {@code
* Attribute} are {@link CustomAttribute}, which all user-defined attributes
* should extend from, and {@link UnknownAttribute}, representing attributes
* read from {@code class} file but are not recognized by the {@link
* ClassFile.AttributeMapperOption}.
* <p>
* Attributes are read through {@link AttributedElement} or element traversal of
* a {@link CompoundElement}; they are written through {@link ClassFileBuilder}.
* See {@linkplain java.lang.classfile.attribute##reading Reading Attributes}
* and {@linkplain java.lang.classfile.attribute##writing Writing Attributes}
* for more details.
*
* @param <A> the attribute type
* @see java.lang.classfile.attribute
* @see AttributeMapper
* @see AttributedElement
* @see CustomAttribute
* @see UnknownAttribute
* @jvms 4.7 Attributes
* @sealedGraph
* @since 24
*/
@@ -62,7 +78,13 @@ public sealed interface Attribute<A extends Attribute<A>>
StackMapTableAttribute, SyntheticAttribute,
UnknownAttribute, BoundAttribute, UnboundAttribute, CustomAttribute {
/**
* {@return the name of the attribute}
* {@return the name of the attribute} The {@linkplain
* Utf8Entry#stringValue() string value} of the name is equivalent to the
* value of {@link AttributeMapper#name() attributeMapper().name()}.
* <p>
* If this attribute is read from a {@code class} file, this method returns
* the {@link Utf8Entry} indicating the attribute name in the {@code class}
* file.
*/
Utf8Entry attributeName();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -24,54 +24,118 @@
*/
package java.lang.classfile;
import java.lang.classfile.attribute.BootstrapMethodsAttribute;
import java.lang.classfile.attribute.CodeAttribute;
import java.lang.classfile.attribute.UnknownAttribute;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.classfile.constantpool.Utf8Entry;
/**
* Bidirectional mapper between the classfile representation of an attribute and
* how that attribute is modeled in the API. The attribute mapper is used
* to parse the classfile representation into a model, and to write the model
* representation back to a classfile. For each standard attribute, there is a
* predefined attribute mapper defined in {@link Attributes}. For nonstandard
* attributes, clients can define their own {@linkplain AttributeMapper}.
* Classes that model nonstandard attributes should extend {@link
* CustomAttribute}.
* @param <A> the attribute type
* Bidirectional mapper between the {@code class} file representation of an
* attribute and its API model. The attribute mapper identifies an attribute
* by its {@linkplain Attribute#attributeName name}, and is used to parse the
* {@code class} file representation into a model, and to write the model
* representation back to a {@code class} file.
* <p>
* {@link Attributes} defines the mappers for predefined attributes in the JVMS
* and certain conventional attributes. For other attributes (JVMS {@jvms
* 4.7.1}), users can define their own {@code AttributeMapper}; classes that
* model those attributes should extend {@link CustomAttribute}. To read those
* attributes, user-defined {@code AttributeMapper}s must be registered to the
* {@link ClassFile.AttributeMapperOption}.
*
* @param <A> the attribute type
* @see Attributes
* @see ClassFile.AttributeMapperOption
* @see java.lang.classfile.attribute
* @since 24
*/
public interface AttributeMapper<A extends Attribute<A>> {
/**
* Attribute stability indicator
* Indicates the data dependency of the {@code class} file representation
* of an attribute. Whether an attribute can be bulk-copied by its binary
* representation to a new {@code class} file depends on if its data refers
* to other parts of its enclosing {@code class} file.
*
* @apiNote
* This dependency is called "stability" because it indicates the conditions
* for a {@code class} file attribute to be eligible for bulk-copying to
* another {@code class} file.
*
* @see AttributeMapper#stability()
* @since 24
*/
enum AttributeStability {
/**
* The attribute contains only pure data, such as timestamps, and can always be bulk-copied.
* The attribute contains only standalone data, and has no reference to
* other parts of its enclosing {@code class} file, besides the name of
* the attribute. Thus, its contents can always be bulk-copied to
* another {@code class} file.
* <p>
* For example, a bit mask is standalone data.
*/
STATELESS,
/**
* The attribute contains only pure data and CP refs, so can be bulk-copied when CP sharing is in effect,
* and need to be exploded and rewritten when CP sharing is not in effect.
* In addition to standalone data, the attribute refers to the constant
* pool, including the {@link BootstrapMethodsAttribute BootstrapMethods}
* attribute, of its enclosing {@code class} file. Thus, it can be
* bulk-copied when the destination {@code class} file extends its
* constant pool from that of the original {@code class}. It must be
* expanded to translate constant pool references and rewritten when
* constant pool indices are not compatible.
* <p>
* For example, a {@link Utf8Entry} is a reference to the constant pool.
*
* @see ConstantPoolBuilder#of(ClassModel)
* @see ClassFile.ConstantPoolSharingOption
*/
CP_REFS,
/**
* The attribute may contain labels, so need to be exploded and rewritten when the Code array is perturbed.
* In addition to standalone data and references to the constant pool,
* the attribute refers to positions into the {@code code} array of a
* {@link CodeAttribute Code} attribute. Thus, it can be bulked-copied
* when the {@code code} array is unchanged, which requires that the
* destination {@code class} file extends its constant pool from that of
* the original {@code class}. It must be expanded to translate {@link
* Label}s or constant pool references and rewritten if the {@code code}
* array is perturbed, including when constant pool indices are not
* compatible.
* <p>
* For example, a bci value, modeled by a {@link Label}, is a reference
* to a position in the {@code code} array.
*/
LABELS,
/**
* The attribute may contain indexes into structured not managed by the library (type variable lists, etc)
* and so we consult the {@link ClassFile.AttributesProcessingOption} option to determine whether to preserve
* or drop it during transformation.
* The attribute refers to structures not managed by the library (type
* variable lists, etc.). As a result, even when the attribute is
* expanded, those references may not be correctly translated, and the
* rewritten results may be incorrect.
* <p>
* If the attribute is read from a {@code class} file, {@link
* ClassFile.AttributesProcessingOption} determines whether to preserve
* or drop the attribute during transformation.
*
* @see ClassFile.AttributesProcessingOption#DROP_UNSTABLE_ATTRIBUTES
*/
UNSTABLE,
/**
* The attribute is completely unknown and so we consult the {@link ClassFile.AttributesProcessingOption} option
* to determine whether to preserve or drop it during transformation.
* The attribute is completely unknown. As a result, expanding and
* rewriting is not possible, and any difference between the destination
* {@code class} file and its enclosing {@code class} file may make the
* attribute incorrect.
* <p>
* {@link ClassFile.AttributesProcessingOption} determines whether to
* preserve or drop the attribute during transformation.
*
* @see UnknownAttribute
* @see ClassFile.AttributesProcessingOption#DROP_UNSTABLE_ATTRIBUTES
* @see ClassFile.AttributesProcessingOption#DROP_UNKNOWN_ATTRIBUTES
*/
UNKNOWN
}
@@ -82,35 +146,104 @@ public interface AttributeMapper<A extends Attribute<A>> {
String name();
/**
* Create an {@link Attribute} instance from a classfile.
* Creates an {@link Attribute} instance from a {@code class} file for the
* Class-File API.
* <p>
* This method is called by the Class-File API to support reading of
* attributes. Users should never call this method.
* <p>
* The Class-File API makes these promises about the call to this method:
* <ul>
* <li>The {@link Utf8Entry} for the name of the attribute is accessible
* with {@code cf.readEntry(pos - 6, Utf8Entry.class)}, and is validated;
* <li>The length of the attribute is accessible with {@code cf.readInt(pos
* - 4)}, and is validated to be positive and not beyond the length of the
* {@code class} file;
* <li>The {@link AttributedElement} attribute access functionalities on the
* {@code enclosing} model may not be accessed when this method is called,
* but can be accessed later by the returned attribute when it is accessible
* to users.
* </ul>
* <p>
* The returned {@code Attribute} must fulfill these requirements:
* <ul>
* <li>{@link Attribute#attributeMapper()} returns this mapper;
* <li>{@link Attribute#attributeName()} returns the attribute name in the
* {@code class} file.
* </ul>
*
* @param enclosing The class, method, field, or code attribute in which
* this attribute appears
* @param cf The {@link ClassReader} describing the classfile to read from
* @param pos The offset into the classfile at which the attribute starts
* @return the new attribute
* @apiNote
* Implementations of this method should perform minimal work to return an
* attribute, as this method is called even if the resulting attribute is
* never used. In particular, the implementation should avoid checking the
* validity of the attribute {@code class} file data or performing actions
* that may throw exceptions.
*
* @param enclosing the structure in which this attribute appears
* @param cf provides access to the {@code class} file to read from
* @param pos the offset into the {@code class} file at which the contents
* of the attribute starts
* @return the read attribute
*/
A readAttribute(AttributedElement enclosing, ClassReader cf, int pos);
/**
* Write an {@link Attribute} instance to a classfile.
* Writes an {@link Attribute} instance to a {@code class} file for the
* Class-File API.
* <p>
* This method is called by the Class-File API to support writing of
* attributes. Users should never call this method.
* <p>
* The Class-File API makes these promises about the call to this method:
* <ul>
* <li>{@link Attribute#attributeMapper() attr.attributeMapper()} returns
* this mapper;
* <li>The {@code buf} may already have data written, that its {@link
* BufWriter#size() size} may not be {@code 0}.
* </ul>
* <p>
* The {@code class} file writing must fulfill these requirements:
* <ul>
* <li>The attribute name {@code u2} and attribute length {@code u4} must
* be written to the {@code buf};
* <li>{@link Attribute#attributeName() attr.attributeName()} is written as
* if with {@code buf.writeIndex(attr.attributeName())};
* <li>The attribute length is the length, in bytes, of attribute contents
* written to the {@code buf}, not including the 6 bytes used by the name
* and the length;
* <li>If any information in the API model of the attribute, {@code attr},
* cannot be represented in the {@code class} file format of the attribute,
* an {@link IllegalArgumentException} is thrown.
* </ul>
*
* @param buf The {@link BufWriter} to which the attribute should be written
* @param attr The attribute to write
* @apiNote
* {@link BufWriter#patchInt} can be used to update the attribute length
* after the attribute contents are written to the {@code buf}.
*
* @param buf the {@link BufWriter} to which the attribute should be written
* @param attr the attribute to write
* @throws IllegalArgumentException if some data in the API model of the
* attribute is invalid for the {@code class} file format
*/
void writeAttribute(BufWriter buf, A attr);
/**
* {@return whether this attribute may appear more than once in a given location}
* {@return whether this attribute may appear more than once in one
* structure}
* <p>
* If an attribute does not allow multiple instances in one structure,
* can be supplied to a {@link ClassFileBuilder}, and multiple instances of
* the attribute are supplied to the builder, the last supplied attribute
* appears on the built structure.
*
* @implSpec The default implementation returns {@code false}
* @implSpec The default implementation returns {@code false}.
*/
default boolean allowMultiple() {
return false;
}
/**
* {@return attribute stability indicator}
* {@return the data dependency of this attribute on the {@code class} file}
*/
AttributeStability stability();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -24,6 +24,7 @@
*/
package java.lang.classfile;
import java.lang.classfile.attribute.CodeAttribute;
import java.lang.classfile.attribute.RecordComponentInfo;
import java.util.ArrayList;
import java.util.Collections;
@@ -35,9 +36,18 @@ import jdk.internal.classfile.impl.AbstractUnboundModel;
import static java.util.Objects.requireNonNull;
/**
* A {@link ClassFileElement} describing an entity that has attributes, such
* as a class, field, method, code attribute, or record component.
* A {@link ClassFileElement} describing a {@code class} file structure that has
* attributes, such as a {@code class} file, a field, a method, a {@link
* CodeAttribute Code} attribute, or a record component.
* <p>
* Unless otherwise specified, most attributes that can be discovered in a
* {@link CompoundElement} implements the corresponding {@linkplain
* ClassFileElement##membership membership subinterface} of {@code
* ClassFileElement}, and can be sent to a {@link ClassFileBuilder} to be
* integrated into the built structure.
*
* @see java.lang.classfile.attribute
* @jvms 4.7 Attributes
* @sealedGraph
* @since 24
*/
@@ -46,15 +56,28 @@ public sealed interface AttributedElement extends ClassFileElement
RecordComponentInfo, AbstractUnboundModel {
/**
* {@return the attributes of this element}
* {@return the attributes of this structure}
*/
List<Attribute<?>> attributes();
/**
* Finds an attribute by name.
* Finds an attribute by name. This is suitable to find attributes that
* {@linkplain AttributeMapper#allowMultiple() allow at most one instance}
* in one structure. If this is used to find attributes that allow multiple
* instances in one structure, the first matching instance is returned.
*
* @apiNote
* This can easily find an attribute and send it to another {@link
* ClassFileBuilder}, which is a {@code Consumer}:
* {@snippet lang=java :
* MethodModel method = null; // @replace substring=null; replacement=...
* MethodBuilder mb = null; // @replace substring=null; replacement=...
* method.findAttribute(Attributes.code()).ifPresent(mb);
* }
*
* @param attr the attribute mapper
* @param <T> the type of the attribute
* @return the attribute, or an empty {@linkplain Optional} if the attribute
* @return the attribute, or {@code Optional.empty()} if the attribute
* is not present
*/
default <T extends Attribute<T>> Optional<T> findAttribute(AttributeMapper<T> attr) {
@@ -70,10 +93,13 @@ public sealed interface AttributedElement extends ClassFileElement
}
/**
* Finds one or more attributes by name.
* Finds attributes by name. This is suitable to find attributes that
* {@linkplain AttributeMapper#allowMultiple() allow multiple instances}
* in one structure.
*
* @param attr the attribute mapper
* @param <T> the type of the attribute
* @return the attributes, or an empty {@linkplain List} if the attribute
* @return the attributes, or an empty {@code List} if the attribute
* is not present
*/
default <T extends Attribute<T>> List<T> findAttributes(AttributeMapper<T> attr) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,64 +30,20 @@ import java.lang.classfile.attribute.*;
import jdk.internal.classfile.impl.AbstractAttributeMapper.*;
/**
* Attribute mappers for standard classfile attributes.
* Attribute mappers for predefined (JVMS {@jvms 4.7}) and JDK-specific
* nonstandard attributes.
* <p>
* Unless otherwise specified, mappers returned by each method
* do not permit multiple attribute instances in a given location.
* <p>
* The most stable {@link AttributeStability#STATELESS STATELESS} mappers are:
* Unless otherwise specified, each mapper returned by methods in this class:
* <ul>
* <li>{@link #deprecated()}
* <li>{@link #moduleResolution()}
* <li>{@link #sourceDebugExtension()}
* <li>{@link #synthetic()}
* </ul>
*
* The mappers with {@link AttributeStability#CP_REFS CP_REFS} stability are:
* <ul>
* <li>{@link #annotationDefault()}
* <li>{@link #bootstrapMethods()}
* <li>{@link #code()}
* <li>{@link #compilationId()}
* <li>{@link #constantValue()}
* <li>{@link #enclosingMethod()}
* <li>{@link #exceptions()}
* <li>{@link #innerClasses()}
* <li>{@link #methodParameters()}
* <li>{@link #module()}
* <li>{@link #moduleHashes()}
* <li>{@link #moduleMainClass()}
* <li>{@link #modulePackages()}
* <li>{@link #moduleTarget()}
* <li>{@link #nestHost()}
* <li>{@link #nestMembers()}
* <li>{@link #permittedSubclasses()}
* <li>{@link #record()}
* <li>{@link #runtimeInvisibleAnnotations()}
* <li>{@link #runtimeInvisibleParameterAnnotations()}
* <li>{@link #runtimeVisibleAnnotations()}
* <li>{@link #runtimeVisibleParameterAnnotations()}
* <li>{@link #signature()}
* <li>{@link #sourceFile()}
* <li>{@link #sourceId()}
* </ul>
*
* The mappers with {@link AttributeStability#LABELS LABELS} stability are:
* <ul>
* <li>{@link #characterRangeTable()}
* <li>{@link #lineNumberTable()}
* <li>{@link #localVariableTable()}
* <li>{@link #localVariableTypeTable()}
* </ul>
*
* The {@link AttributeStability#UNSTABLE UNSTABLE} mappers are:
* <ul>
* <li>{@link #runtimeInvisibleTypeAnnotations()}
* <li>{@link #runtimeVisibleTypeAnnotations()}
* <li>is predefined in the JVMS instead of JDK-specific;
* <li>does not permit {@linkplain AttributeMapper#allowMultiple() multiple
* attribute instances} in the same structure;
* <li>the attribute has a {@linkplain AttributeMapper#stability() data
* dependency} on the {@linkplain AttributeStability#CP_REFS constant pool}.
* </ul>
*
* @see AttributeMapper
*
* @see java.lang.classfile.attribute
* @since 24
*/
public final class Attributes {
@@ -204,258 +160,278 @@ public final class Attributes {
}
/**
* {@return Attribute mapper for the {@code AnnotationDefault} attribute}
* {@return the mapper for the {@code AnnotationDefault} attribute}
*/
public static AttributeMapper<AnnotationDefaultAttribute> annotationDefault() {
return AnnotationDefaultMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code BootstrapMethods} attribute}
* {@return the mapper for the {@code BootstrapMethods} attribute}
*/
public static AttributeMapper<BootstrapMethodsAttribute> bootstrapMethods() {
return BootstrapMethodsMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code CharacterRangeTable} attribute}
* The mapper permits multiple instances in a given location.
* {@return the mapper for the {@code CharacterRangeTable} attribute}
* This is a JDK-specific attribute.
* The mapper permits multiple instances in a {@code Code} attribute, but this
* attribute should be only emitted once.
* This has a data dependency on {@linkplain AttributeStability#LABELS labels}.
*/
public static AttributeMapper<CharacterRangeTableAttribute> characterRangeTable() {
return CharacterRangeTableMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code Code} attribute}
* {@return the mapper for the {@code Code} attribute}
*/
public static AttributeMapper<CodeAttribute> code() {
return CodeMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code CompilationID} attribute}
* {@return the mapper for the {@code CompilationID} attribute}
* This is a JDK-specific attribute.
*/
public static AttributeMapper<CompilationIDAttribute> compilationId() {
return CompilationIDMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code ConstantValue} attribute}
* {@return the mapper for the {@code ConstantValue} attribute}
*/
public static AttributeMapper<ConstantValueAttribute> constantValue() {
return ConstantValueMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code Deprecated} attribute}
* {@return the mapper for the {@code Deprecated} attribute}
* The mapper permits multiple instances in a given location.
* This has {@linkplain AttributeStability#STATELESS no data dependency}.
*/
public static AttributeMapper<DeprecatedAttribute> deprecated() {
return DeprecatedMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code EnclosingMethod} attribute}
* {@return the mapper for the {@code EnclosingMethod} attribute}
*/
public static AttributeMapper<EnclosingMethodAttribute> enclosingMethod() {
return EnclosingMethodMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code Exceptions} attribute}
* {@return the mapper for the {@code Exceptions} attribute}
*/
public static AttributeMapper<ExceptionsAttribute> exceptions() {
return ExceptionsMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code InnerClasses} attribute}
* {@return the mapper for the {@code InnerClasses} attribute}
*/
public static AttributeMapper<InnerClassesAttribute> innerClasses() {
return InnerClassesMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code LineNumberTable} attribute}
* The mapper permits multiple instances in a given location.
* {@return the mapper for the {@code LineNumberTable} attribute}
* The mapper permits multiple instances in a {@code Code} attribute.
* This has a data dependency on {@linkplain AttributeStability#LABELS labels}.
*/
public static AttributeMapper<LineNumberTableAttribute> lineNumberTable() {
return LineNumberTableMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code LocalVariableTable} attribute}
* The mapper permits multiple instances in a given location.
* {@return the mapper for the {@code LocalVariableTable} attribute}
* The mapper permits multiple instances in a {@code Code} attribute.
* This has a data dependency on {@linkplain AttributeStability#LABELS labels}.
*/
public static AttributeMapper<LocalVariableTableAttribute> localVariableTable() {
return LocalVariableTableMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code LocalVariableTypeTable} attribute}
* {@return the mapper for the {@code LocalVariableTypeTable} attribute}
* The mapper permits multiple instances in a given location.
* This has a data dependency on {@linkplain AttributeStability#LABELS labels}.
*/
public static AttributeMapper<LocalVariableTypeTableAttribute> localVariableTypeTable() {
return LocalVariableTypeTableMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code MethodParameters} attribute}
* {@return the mapper for the {@code MethodParameters} attribute}
*/
public static AttributeMapper<MethodParametersAttribute> methodParameters() {
return MethodParametersMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code Module} attribute}
* {@return the mapper for the {@code Module} attribute}
*/
public static AttributeMapper<ModuleAttribute> module() {
return ModuleMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code ModuleHashes} attribute}
* {@return the mapper for the {@code ModuleHashes} attribute}
* This is a JDK-specific attribute.
*/
public static AttributeMapper<ModuleHashesAttribute> moduleHashes() {
return ModuleHashesMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code ModuleMainClass} attribute}
* {@return the mapper for the {@code ModuleMainClass} attribute}
*/
public static AttributeMapper<ModuleMainClassAttribute> moduleMainClass() {
return ModuleMainClassMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code ModulePackages} attribute}
* {@return the mapper for the {@code ModulePackages} attribute}
*/
public static AttributeMapper<ModulePackagesAttribute> modulePackages() {
return ModulePackagesMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code ModuleResolution} attribute}
* {@return the mapper for the {@code ModuleResolution} attribute}
* This is a JDK-specific attribute.
* This has {@linkplain AttributeStability#STATELESS no data dependency}.
*/
public static AttributeMapper<ModuleResolutionAttribute> moduleResolution() {
return ModuleResolutionMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code ModuleTarget} attribute}
* {@return the mapper for the {@code ModuleTarget} attribute}
* This is a JDK-specific attribute.
*/
public static AttributeMapper<ModuleTargetAttribute> moduleTarget() {
return ModuleTargetMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code NestHost} attribute}
* {@return the mapper for the {@code NestHost} attribute}
*/
public static AttributeMapper<NestHostAttribute> nestHost() {
return NestHostMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code NestMembers} attribute}
* {@return the mapper for the {@code NestMembers} attribute}
*/
public static AttributeMapper<NestMembersAttribute> nestMembers() {
return NestMembersMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code PermittedSubclasses} attribute}
* {@return the mapper for the {@code PermittedSubclasses} attribute}
*/
public static AttributeMapper<PermittedSubclassesAttribute> permittedSubclasses() {
return PermittedSubclassesMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code Record} attribute}
* {@return the mapper for the {@code Record} attribute}
*/
public static AttributeMapper<RecordAttribute> record() {
return RecordMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code RuntimeInvisibleAnnotations} attribute}
* {@return the mapper for the {@code RuntimeInvisibleAnnotations} attribute}
*/
public static AttributeMapper<RuntimeInvisibleAnnotationsAttribute> runtimeInvisibleAnnotations() {
return RuntimeInvisibleAnnotationsMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code RuntimeInvisibleParameterAnnotations} attribute}
* {@return the mapper for the {@code RuntimeInvisibleParameterAnnotations} attribute}
*/
public static AttributeMapper<RuntimeInvisibleParameterAnnotationsAttribute> runtimeInvisibleParameterAnnotations() {
return RuntimeInvisibleParameterAnnotationsMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code RuntimeInvisibleTypeAnnotations} attribute}
* {@return the mapper for the {@code RuntimeInvisibleTypeAnnotations} attribute}
* This has a data dependency on {@linkplain AttributeStability#UNSTABLE
* arbitrary indices} in the {@code class} file format.
*/
public static AttributeMapper<RuntimeInvisibleTypeAnnotationsAttribute> runtimeInvisibleTypeAnnotations() {
return RuntimeInvisibleTypeAnnotationsMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code RuntimeVisibleAnnotations} attribute}
* {@return the mapper for the {@code RuntimeVisibleAnnotations} attribute}
*/
public static AttributeMapper<RuntimeVisibleAnnotationsAttribute> runtimeVisibleAnnotations() {
return RuntimeVisibleAnnotationsMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code RuntimeVisibleParameterAnnotations} attribute}
* {@return the mapper for the {@code RuntimeVisibleParameterAnnotations} attribute}
*/
public static AttributeMapper<RuntimeVisibleParameterAnnotationsAttribute> runtimeVisibleParameterAnnotations() {
return RuntimeVisibleParameterAnnotationsMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code RuntimeVisibleTypeAnnotations} attribute}
* {@return the mapper for the {@code RuntimeVisibleTypeAnnotations} attribute}
* This has a data dependency on {@linkplain AttributeStability#UNSTABLE
* arbitrary indices} in the {@code class} file format.
*/
public static AttributeMapper<RuntimeVisibleTypeAnnotationsAttribute> runtimeVisibleTypeAnnotations() {
return RuntimeVisibleTypeAnnotationsMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code Signature} attribute}
* {@return the mapper for the {@code Signature} attribute}
*/
public static AttributeMapper<SignatureAttribute> signature() {
return SignatureMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code SourceDebugExtension} attribute}
* {@return the mapper for the {@code SourceDebugExtension} attribute}
* This has {@linkplain AttributeStability#STATELESS no data dependency}.
*/
public static AttributeMapper<SourceDebugExtensionAttribute> sourceDebugExtension() {
return SourceDebugExtensionMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code SourceFile} attribute}
* {@return the mapper for the {@code SourceFile} attribute}
*/
public static AttributeMapper<SourceFileAttribute> sourceFile() {
return SourceFileMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code SourceID} attribute}
* {@return the mapper for the {@code SourceID} attribute}
* This is a JDK-specific attribute.
*/
public static AttributeMapper<SourceIDAttribute> sourceId() {
return SourceIDMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code StackMapTable} attribute}
* {@return the mapper for the {@code StackMapTable} attribute}
* This has a data dependency on {@linkplain AttributeStability#LABELS labels}.
*/
public static AttributeMapper<StackMapTableAttribute> stackMapTable() {
return StackMapTableMapper.INSTANCE;
}
/**
* {@return Attribute mapper for the {@code Synthetic} attribute}
* {@return the mapper for the {@code Synthetic} attribute}
* The mapper permits multiple instances in a given location.
* This has {@linkplain AttributeStability#STATELESS no data dependency}.
*/
public static AttributeMapper<SyntheticAttribute> synthetic() {
return SyntheticMapper.INSTANCE;

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -25,7 +25,9 @@
package java.lang.classfile;
import java.lang.classfile.attribute.BootstrapMethodsAttribute;
import java.lang.classfile.constantpool.ConstantPool;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.classfile.constantpool.LoadableConstantEntry;
import java.lang.classfile.constantpool.MethodHandleEntry;
import java.util.List;
@@ -34,10 +36,20 @@ import jdk.internal.classfile.impl.BootstrapMethodEntryImpl;
/**
* Models an entry in the bootstrap method table. The bootstrap method table
* is stored in the {@code BootstrapMethods} attribute, but is modeled by
* the {@link ConstantPool}, since the bootstrap method table is logically
* part of the constant pool.
* is stored in the {@link BootstrapMethodsAttribute BootstrapMethods}
* attribute, but is modeled by the {@link ConstantPool}, since the bootstrap
* method table is logically part of the constant pool.
* <p>
* A bootstrap method entry is composite:
* {@snippet lang=text :
* // @link substring="BootstrapMethodEntry" target="ConstantPoolBuilder#bsmEntry(MethodHandleEntry, List)" :
* BootstrapMethodEntry(
* MethodHandleEntry bootstrapMethod, // @link substring="bootstrapMethod" target="#bootstrapMethod"
* List<LoadableConstantEntry> arguments // @link substring="arguments" target="#arguments()"
* )
* }
*
* @see ConstantPoolBuilder#bsmEntry ConstantPoolBuilder::bsmEntry
* @since 24
*/
public sealed interface BootstrapMethodEntry
@@ -45,11 +57,19 @@ public sealed interface BootstrapMethodEntry
/**
* {@return the constant pool associated with this entry}
*
* @apiNote
* Given a {@link ConstantPoolBuilder} {@code builder} and a {@code
* BootstrapMethodEntry} {@code entry}, use {@link
* ConstantPoolBuilder#canWriteDirect
* builder.canWriteDirect(entry.constantPool())} instead of object equality
* of the constant pool to determine if an entry is compatible.
*/
ConstantPool constantPool();
/**
* {@return the index into the bootstrap method table corresponding to this entry}
* {@return the index into the bootstrap method table corresponding to this
* entry}
*/
int bsmIndex();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -27,120 +27,163 @@ package java.lang.classfile;
import java.lang.classfile.constantpool.ConstantPool;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.classfile.constantpool.PoolEntry;
import java.nio.ByteOrder;
import jdk.internal.classfile.impl.BufWriterImpl;
/**
* Supports writing portions of a classfile to a growable buffer. Methods
* are provided to write various standard entities (e.g., {@code u2}, {@code u4})
* to the end of the buffer, as well as to create constant pool entries.
* Advanced {@code class} file writing support for {@link AttributeMapper}s.
* Supports writing portions of a {@code class} file to a growable buffer, such
* as writing various numerical types (e.g., {@code u2}, {@code u4}), to the end
* of the buffer, as well as to create constant pool entries.
* <p>
* All numeric values in the {@code class} file format are {@linkplain
* ByteOrder#BIG_ENDIAN big endian}. Writing larger numeric values to smaller
* numeric values are always done with truncation, that the least significant
* bytes are kept and the other bytes are silently dropped. As a result,
* numeric value writing methods can write both signed and unsigned values, and
* users should validate their values before writing if silent dropping of most
* significant bytes is not the intended behavior.
*
* @see AttributeMapper#writeAttribute(BufWriter, Attribute)
* @since 24
*/
public sealed interface BufWriter
permits BufWriterImpl {
/** {@return the constant pool builder associated with this buffer} */
/**
* {@return the constant pool builder associated with this buffer}
*
* @see ClassFileBuilder#constantPool()
*/
ConstantPoolBuilder constantPool();
/**
* {@return whether the provided constant pool is index-compatible with this
* one} This may be because they are the same constant pool, or because this
* constant pool was copied from the other.
* {@return whether the provided constant pool is index-compatible with the
* constant pool of this buffer}
* <p>
* This is a shortcut for {@code constantPool().canWriteDirect(other)}.
*
* @param other the other constant pool
* @see ConstantPoolBuilder#canWriteDirect(ConstantPool)
*/
boolean canWriteDirect(ConstantPool other);
/**
* Ensure that the buffer has at least {@code freeBytes} bytes of unused space
* Ensures that the buffer has at least {@code freeBytes} bytes of free space
* in the end of the buffer.
* <p>
* The writing result is the same without calls to this method, but the
* writing process may be slower.
*
* @apiNote
* This is a hint that changes no visible state of the buffer; it helps to
* reduce reallocation of the underlying storage by allocating sufficient
* space at once.
*
* @param freeBytes the number of bytes to reserve
*/
void reserveSpace(int freeBytes);
/**
* Write an unsigned byte to the buffer
* Writes a byte to the buffer. {@code x} is truncated to a byte and
* written.
*
* @param x the byte value
* @param x the value to truncate to a byte
*/
void writeU1(int x);
/**
* Write an unsigned short to the buffer
* Writes 2 bytes, or a short, to the buffer. {@code x} is truncated to two
* bytes and written.
*
* @param x the short value
* @param x the value to truncate to a short
*/
void writeU2(int x);
/**
* Write a signed int to the buffer
* Writes 4 bytes, or an int, to the buffer.
*
* @param x the int value
*/
void writeInt(int x);
/**
* Write a float value to the buffer
* Writes a float value, of 4 bytes, to the buffer.
* <p>
* In the conversions, all NaN values of the {@code float} may or may not be
* collapsed into a single {@linkplain Float#NaN "canonical" NaN value}.
*
* @param x the float value
*/
void writeFloat(float x);
/**
* Write a long value to the buffer
* Writes 8 bytes, or a long, to the buffer.
*
* @param x the long value
*/
void writeLong(long x);
/**
* Write a double value to the buffer
* Writes a double value, of 8 bytes, to the buffer.
* <p>
* In the conversions, all NaN values of the {@code double} may or may not
* be collapsed into a single {@linkplain Double#NaN "canonical" NaN value}.
*
* @param x the int value
* @param x the double value
*/
void writeDouble(double x);
/**
* Write the contents of a byte array to the buffer
* Writes the contents of a byte array to the buffer.
*
* @param arr the byte array
*/
void writeBytes(byte[] arr);
/**
* Write a range of a byte array to the buffer
* Writes a range of a byte array to the buffer.
*
* @param arr the byte array
* @param start the offset within the byte array of the range
* @param start the start offset of the range within the byte array
* @param length the length of the range
* @throws IndexOutOfBoundsException if range is outside of the array bounds
* @throws IndexOutOfBoundsException if range is outside the array bounds
*/
void writeBytes(byte[] arr, int start, int length);
/**
* Patch a previously written integer value. Depending on the specified
* size, the entire value, or the low 1 or 2 bytes, may be written.
* Patches a previously written integer value. {@code value} is truncated
* to the given {@code size} number of bytes and written at the given {@code
* offset}. The end of this buffer stays unchanged.
*
* @param offset the offset at which to patch
* @apiNote
* The {@code offset} can be obtained by calling {@link #size()} before
* writing the previous integer value.
*
* @param offset the offset in this buffer at which to patch
* @param size the size of the integer value being written, in bytes
* @param value the integer value
* @param value the integer value to be truncated
* @throws IndexOutOfBoundsException if patched int is outside of bounds
* @see #size()
*/
void patchInt(int offset, int size, int value);
/**
* Write a 1, 2, 4, or 8 byte integer value to the buffer. Depending on
* the specified size, the entire value, or the low 1, 2, or 4 bytes, may
* be written.
* Writes a multibyte value to the buffer. {@code intValue} is truncated
* to the given {@code intSize} number of bytes and written.
*
* @param intSize the size of the integer value being written, in bytes
* @param intValue the integer value
* @param intValue the value to be truncated
*/
void writeIntBytes(int intSize, long intValue);
/**
* Write the index of the specified constant pool entry, as a {@code u2},
* to the buffer
* Writes the index of the specified constant pool entry as a {@link
* #writeU2 u2}. If the {@code entry} does not belong to the {@linkplain
* #constantPool() constant pool} of this buffer, it will be {@linkplain
* ConstantPoolBuilder##alien converted}, and the index of the converted
* pool entry is written instead.
*
* @param entry the constant pool entry
* @throws IllegalArgumentException if the entry has invalid index
@@ -148,16 +191,23 @@ public sealed interface BufWriter
void writeIndex(PoolEntry entry);
/**
* Write the index of the specified constant pool entry, as a {@code u2},
* to the buffer, or zero if the entry is null
* Writes the index of the specified constant pool entry, or the value
* {@code 0} if the specified entry is {@code null}, as a {@link #writeU2
* u2}. If the {@code entry} does not belong to the {@linkplain
* #constantPool() constant pool} of this buffer, it will be {@linkplain
* ConstantPoolBuilder##alien converted}, and the index of the converted
* pool entry is written instead.
*
* @param entry the constant pool entry
* @throws IllegalArgumentException if the entry has invalid index
* @param entry the constant pool entry, may be {@code null}
* @throws IllegalArgumentException if the entry is not {@code null} and has
* invalid index
*/
void writeIndexOrZero(PoolEntry entry);
/**
* {@return the number of bytes that have been written to the buffer}
*
* @see #patchInt(int, int, int)
*/
int size();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -25,8 +25,8 @@
package java.lang.classfile;
import java.lang.classfile.attribute.CodeAttribute;
import java.lang.classfile.constantpool.ClassEntry;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.classfile.constantpool.Utf8Entry;
import java.lang.constant.ClassDesc;
import java.lang.constant.MethodTypeDesc;
@@ -41,14 +41,19 @@ import jdk.internal.classfile.impl.DirectClassBuilder;
import jdk.internal.classfile.impl.Util;
/**
* A builder for classfiles. Builders are not created directly; they are passed
* to handlers by methods such as {@link ClassFile#build(ClassDesc, Consumer)}
* or to class transforms. The elements of a classfile can be specified
* abstractly (by passing a {@link ClassElement} to {@link #with(ClassFileElement)})
* or concretely by calling the various {@code withXxx} methods.
* A builder for a {@code class} file. {@link ClassFile} provides different
* {@code build} methods that accept handlers to configure such a builder;
* {@link ClassFile#build(ClassDesc, Consumer)} suffices for basic usage, while
* {@link ClassFile#build(ClassEntry, ConstantPoolBuilder, Consumer)} allows
* fine-grained control over {@linkplain ClassFileBuilder#constantPool() the
* constant pool}.
* <p>
* Refer to {@link ClassFileBuilder} for general guidance and caution around
* the use of builders for structures in the {@code class} file format.
*
* @see ClassFile#build(ClassEntry, ConstantPoolBuilder, Consumer)
* @see ClassModel
* @see ClassTransform
*
* @since 24
*/
public sealed interface ClassBuilder
@@ -56,28 +61,38 @@ public sealed interface ClassBuilder
permits ChainedClassBuilder, DirectClassBuilder {
/**
* Sets the classfile version.
* Sets the version of this class.
*
* @param major the major version number
* @param minor the minor version number
* @return this builder
* @see ClassFileVersion
*/
default ClassBuilder withVersion(int major, int minor) {
return with(ClassFileVersion.of(major, minor));
}
/**
* Sets the classfile access flags.
* Sets the access flags of this class.
*
* @param flags the access flags, as a bit mask
* @return this builder
* @see AccessFlags
* @see AccessFlag.Location#CLASS
*/
default ClassBuilder withFlags(int flags) {
return with(new AccessFlagsImpl(AccessFlag.Location.CLASS, flags));
}
/**
* Sets the classfile access flags.
* @param flags the access flags
* Sets the access flags of this class.
*
* @param flags the access flags, as flag enums
* @return this builder
* @throws IllegalArgumentException if any flag cannot be applied to the
* {@link AccessFlag.Location#CLASS} location
* @see AccessFlags
* @see AccessFlag.Location#CLASS
*/
default ClassBuilder withFlags(AccessFlag... flags) {
return with(new AccessFlagsImpl(AccessFlag.Location.CLASS, flags));
@@ -85,8 +100,10 @@ public sealed interface ClassBuilder
/**
* Sets the superclass of this class.
*
* @param superclassEntry the superclass
* @return this builder
* @see Superclass
*/
default ClassBuilder withSuperclass(ClassEntry superclassEntry) {
return with(Superclass.of(superclassEntry));
@@ -94,9 +111,11 @@ public sealed interface ClassBuilder
/**
* Sets the superclass of this class.
*
* @param desc the superclass
* @return this builder
* @throws IllegalArgumentException if {@code desc} represents a primitive type
* @see Superclass
*/
default ClassBuilder withSuperclass(ClassDesc desc) {
return withSuperclass(constantPool().classEntry(desc));
@@ -104,8 +123,10 @@ public sealed interface ClassBuilder
/**
* Sets the interfaces of this class.
*
* @param interfaces the interfaces
* @return this builder
* @see Interfaces
*/
default ClassBuilder withInterfaces(List<ClassEntry> interfaces) {
return with(Interfaces.of(interfaces));
@@ -113,8 +134,10 @@ public sealed interface ClassBuilder
/**
* Sets the interfaces of this class.
*
* @param interfaces the interfaces
* @return this builder
* @see Interfaces
*/
default ClassBuilder withInterfaces(ClassEntry... interfaces) {
return withInterfaces(List.of(interfaces));
@@ -122,8 +145,11 @@ public sealed interface ClassBuilder
/**
* Sets the interfaces of this class.
*
* @param interfaces the interfaces
* @return this builder
* @throws IllegalArgumentException if any element of {@code interfaces} is primitive
* @see Interfaces
*/
default ClassBuilder withInterfaceSymbols(List<ClassDesc> interfaces) {
return withInterfaces(Util.entryList(interfaces));
@@ -131,32 +157,39 @@ public sealed interface ClassBuilder
/**
* Sets the interfaces of this class.
*
* @param interfaces the interfaces
* @return this builder
* @throws IllegalArgumentException if any element of {@code interfaces} is primitive
* @see Interfaces
*/
default ClassBuilder withInterfaceSymbols(ClassDesc... interfaces) {
// List view, since ref to interfaces is temporary
// list version does defensive copy
return withInterfaceSymbols(Arrays.asList(interfaces));
}
/**
* Adds a field.
* @param name the name of the field
* @param descriptor the field descriptor
* @param handler handler which receives a {@link FieldBuilder} which can
* further define the contents of the field
*
* @param name the field name
* @param descriptor the field descriptor string
* @param handler handler to supply the contents of the field
* @return this builder
* @see FieldModel
*/
ClassBuilder withField(Utf8Entry name,
Utf8Entry descriptor,
Consumer<? super FieldBuilder> handler);
/**
* Adds a field.
* @param name the name of the field
* @param descriptor the field descriptor
* @param flags the access flags for this field
* Adds a field, with only access flags.
*
* @param name the field name
* @param descriptor the field descriptor string
* @param flags the access flags for this field, as a bit mask
* @return this builder
* @see FieldModel
* @see FieldBuilder#withFlags(int)
*/
default ClassBuilder withField(Utf8Entry name,
Utf8Entry descriptor,
@@ -166,11 +199,12 @@ public sealed interface ClassBuilder
/**
* Adds a field.
* @param name the name of the field
* @param descriptor the field descriptor
* @param handler handler which receives a {@link FieldBuilder} which can
* further define the contents of the field
*
* @param name the field name
* @param descriptor the symbolic field descriptor
* @param handler handler to supply the contents of the field
* @return this builder
* @see FieldModel
*/
default ClassBuilder withField(String name,
ClassDesc descriptor,
@@ -181,11 +215,14 @@ public sealed interface ClassBuilder
}
/**
* Adds a field.
* @param name the name of the field
* @param descriptor the field descriptor
* @param flags the access flags for this field
* Adds a field, with only access flags.
*
* @param name the field name
* @param descriptor the symbolic field descriptor
* @param flags the access flags for this field, as a bit mask
* @return this builder
* @see FieldModel
* @see FieldBuilder#withFlags(int)
*/
default ClassBuilder withField(String name,
ClassDesc descriptor,
@@ -197,28 +234,33 @@ public sealed interface ClassBuilder
/**
* Adds a field by transforming a field from another class.
*
* @implNote
* <p>This method behaves as if:
* <p>
* This method behaves as if:
* {@snippet lang=java :
* withField(field.fieldName(), field.fieldType(),
* b -> b.transformField(field, transform));
* // @link substring=withField target="#withField(Utf8Entry, Utf8Entry, Consumer)" :
* withField(field.fieldName(), field.fieldType(),
* fb -> fb.transform(field, transform)) // @link regex="transform(?=\()" target="FieldBuilder#transform"
* }
*
* @param field the field to be transformed
* @param transform the transform to apply to the field
* @return this builder
* @see FieldTransform
*/
ClassBuilder transformField(FieldModel field, FieldTransform transform);
/**
* Adds a method.
* @param name the name of the method
* Adds a method. The bit for {@link ClassFile#ACC_STATIC ACC_STATIC} flag
* cannot be modified by the {@code handler} later, and must be set through
* {@code methodFlags}.
*
* @param name the method name
* @param descriptor the method descriptor
* @param methodFlags the access flags
* @param handler handler which receives a {@link MethodBuilder} which can
* further define the contents of the method
* @param methodFlags the access flags as a bit mask, with the {@code
* ACC_STATIC} bit definitely set
* @param handler handler to supply the contents of the method
* @return this builder
* @see MethodModel
*/
ClassBuilder withMethod(Utf8Entry name,
Utf8Entry descriptor,
@@ -226,14 +268,23 @@ public sealed interface ClassBuilder
Consumer<? super MethodBuilder> handler);
/**
* Adds a method, with only a {@code Code} attribute.
* Adds a method, with only access flags and a {@link CodeModel}. The bit
* for {@link ClassFile#ACC_STATIC ACC_STATIC} flag cannot be modified by
* the {@code handler} later, and must be set through {@code methodFlags}.
* <p>
* This method behaves as if:
* {@snippet lang=java :
* // @link substring=withMethod target="#withMethod(Utf8Entry, Utf8Entry, int, Consumer)" :
* withMethod(name, descriptor, methodFlags, mb -> mb.withCode(handler)) // @link substring=withCode target="MethodBuilder#withCode"
* }
*
* @param name the name of the method
* @param name the method name
* @param descriptor the method descriptor
* @param methodFlags the access flags
* @param handler handler which receives a {@link CodeBuilder} which can
* define the contents of the method body
* @param methodFlags the access flags as a bit mask, with the {@code
* ACC_STATIC} bit definitely set
* @param handler handler to supply the contents of the method body
* @return this builder
* @see MethodModel
*/
default ClassBuilder withMethodBody(Utf8Entry name,
Utf8Entry descriptor,
@@ -243,13 +294,17 @@ public sealed interface ClassBuilder
}
/**
* Adds a method.
* @param name the name of the method
* Adds a method. The bit for {@link ClassFile#ACC_STATIC ACC_STATIC} flag
* cannot be modified by the {@code handler}, and must be set through
* {@code methodFlags}.
*
* @param name the method name
* @param descriptor the method descriptor
* @param methodFlags the access flags
* @param handler handler which receives a {@link MethodBuilder} which can
* further define the contents of the method
* @param methodFlags the access flags as a bit mask, with the {@code
* ACC_STATIC} bit definitely set
* @param handler handler to supply the contents of the method
* @return this builder
* @see MethodModel
*/
default ClassBuilder withMethod(String name,
MethodTypeDesc descriptor,
@@ -262,13 +317,23 @@ public sealed interface ClassBuilder
}
/**
* Adds a method, with only a {@link CodeAttribute}.
* @param name the name of the method
* Adds a method, with only access flags and a {@link CodeModel}. The bit
* for {@link ClassFile#ACC_STATIC ACC_STATIC} flag cannot be modified by
* the {@code handler}, and must be set through {@code methodFlags}.
* <p>
* This method behaves as if:
* {@snippet lang=java :
* // @link substring=withMethod target="#withMethod(String, MethodTypeDesc, int, Consumer)" :
* withMethod(name, descriptor, methodFlags, mb -> mb.withCode(handler)) // @link substring=withCode target="MethodBuilder#withCode"
* }
*
* @param name the method name
* @param descriptor the method descriptor
* @param methodFlags the access flags
* @param handler handler which receives a {@link CodeBuilder} which can
* define the contents of the method body
* @param methodFlags the access flags as a bit mask, with the {@code
* ACC_STATIC} bit definitely set
* @param handler handler to supply the contents of the method body
* @return this builder
* @see MethodModel
*/
default ClassBuilder withMethodBody(String name,
MethodTypeDesc descriptor,
@@ -278,17 +343,21 @@ public sealed interface ClassBuilder
}
/**
* Adds a method by transforming a method from another class.
*
* @implNote
* <p>This method behaves as if:
* Adds a method by transforming a method from another class. The transform
* cannot modify the {@link ClassFile#ACC_STATIC ACC_STATIC} flag of the
* original method.
* <p>
* This method behaves as if:
* {@snippet lang=java :
* withMethod(method.methodName(), method.methodType(),
* b -> b.transformMethod(method, transform));
* // @link substring=withMethod target="#withMethod(Utf8Entry, Utf8Entry, int, Consumer)" :
* withMethod(method.methodName(), method.methodType(), method.flags().flagMask(),
* mb -> mb.transform(method, transform)) // @link regex="transform(?=\()" target="MethodBuilder#transform"
* }
*
* @param method the method to be transformed
* @param transform the transform to apply to the method
* @return this builder
* @see MethodTransform
*/
ClassBuilder transformMethod(MethodModel method, MethodTransform transform);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -27,9 +27,21 @@ package java.lang.classfile;
import java.lang.classfile.attribute.*;
/**
* A marker interface for elements that can appear when traversing
* a {@link ClassModel} or be presented to a {@link ClassBuilder}.
* Marker interface for a member element of a {@link ClassModel}. Such an
* element can appear when traversing a {@link ClassModel} unless otherwise
* specified, be supplied to a {@link ClassBuilder}, and be processed by a
* {@link ClassTransform}.
* <p>
* {@link AccessFlags}, and {@link ClassFileVersion} are member elements of a
* class that appear exactly once during the traversal of a {@link ClassModel}.
* {@link Superclass} and {@link Interfaces} may be absent or appear at most
* once. A {@link ClassBuilder} may provide an alternative superclass if it is
* not defined but required.
*
* @see ClassFileElement##membership Membership Elements
* @see MethodElement
* @see FieldElement
* @see CodeElement
* @sealedGraph
* @since 24
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -31,17 +31,36 @@ import java.util.function.Consumer;
import jdk.internal.classfile.impl.TransformImpl;
/**
* A builder for a classfile or portion of a classfile. Builders are rarely
* created directly; they are passed to handlers by methods such as
* {@link ClassFile#build(ClassDesc, Consumer)} or to transforms.
* Elements of the newly built entity can be specified
* abstractly (by passing a {@link ClassFileElement} to {@link #with(ClassFileElement)}
* or concretely by calling the various {@code withXxx} methods.
* A builder for a {@link CompoundElement}, which accepts the member elements
* to be integrated into the built structure. Builders are usually passed as
* an argument to {@link Consumer} handlers, such as in {@link
* ClassFile#build(ClassDesc, Consumer)}. The handlers should deliver elements
* to a builder similar to how a {@link CompoundElement} traverses its member
* elements.
* <p>
* The basic way a builder accepts elements is through {@link #with}, which
* supports call chaining. Concrete subtypes of builders usually define extra
* methods to define elements directly to the builder, such as {@link
* ClassBuilder#withFlags(int)} or {@link CodeBuilder#aload(int)}.
* <p>
* Whether a member element can appear multiple times in a compound structure
* affects the behavior of the element in {@code ClassFileBuilder}s. If an
* element can appear at most once but multiple instances are supplied to a
* {@code ClassFileBuilder}, the last supplied instance appears on the built
* structure. If an element appears exactly once but no instance is supplied,
* an unspecified default value element may be used in that structure.
* <p>
* Due to restrictions of the {@code class} file format, certain member elements
* that can be modeled by the API cannot be represented in the built structure
* under specific circumstances. Passing such elements to the builder causes
* {@link IllegalArgumentException}. Some {@link ClassFile.Option}s control
* whether such elements should be altered or dropped to produce valid {@code
* class} files.
*
* @param <E> the element type
* @param <B> the builder type
* @param <E> the member element type
* @param <B> the self type of this builder
* @see CompoundElement
* @see ClassFileTransform
*
* @sealedGraph
* @since 24
*/
@@ -49,8 +68,15 @@ public sealed interface ClassFileBuilder<E extends ClassFileElement, B extends C
extends Consumer<E> permits ClassBuilder, FieldBuilder, MethodBuilder, CodeBuilder {
/**
* Integrate the {@link ClassFileElement} into the entity being built.
* @param e the element
* Integrates the member element into the structure being built.
*
* @apiNote
* This method exists to implement {@link Consumer}; users can use {@link
* #with} for call chaining.
*
* @param e the member element
* @throws IllegalArgumentException if the member element cannot be
* represented in the {@code class} file format
*/
@Override
default void accept(E e) {
@@ -58,9 +84,12 @@ public sealed interface ClassFileBuilder<E extends ClassFileElement, B extends C
}
/**
* Integrate the {@link ClassFileElement} into the entity being built.
* @param e the element
* Integrates the member element into the structure being built.
*
* @param e the member element
* @return this builder
* @throws IllegalArgumentException if the member element cannot be
* represented in the {@code class} file format
*/
B with(E e);
@@ -70,10 +99,29 @@ public sealed interface ClassFileBuilder<E extends ClassFileElement, B extends C
ConstantPoolBuilder constantPool();
/**
* Apply a transform to a model, directing results to this builder.
* @param model the model to transform
* Applies a transform to a compound structure, directing results to this
* builder.
* <p>
* The transform will receive each element of the compound structure, as
* well as this builder for building the structure. The transform is free
* to preserve, remove, or replace elements as it sees fit.
* <p>
* A builder can run multiple transforms against different compound
* structures, integrating member elements of different origins.
*
* @apiNote
* Many subinterfaces have methods like {@link ClassBuilder#transformMethod}
* or {@link MethodBuilder#transformCode}. However, calling them is
* fundamentally different from calling this method: those methods call the
* {@code transform} on the child builders instead of on itself. For
* example, {@code classBuilder.transformMethod} calls {@code
* methodBuilder.transform} with a new method builder instead of calling
* {@code classBuilder.transform} on itself.
*
* @param model the structure to transform
* @param transform the transform to apply
* @return this builder
* @see ClassFileTransform
*/
default B transform(CompoundElement<E> model, ClassFileTransform<?, E, B> transform) {
@SuppressWarnings("unchecked")

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -25,12 +25,34 @@
package java.lang.classfile;
/**
* Immutable model for a portion of (or the entirety of) a classfile. Elements
* that model parts of the classfile that have attributes will implement {@link
* AttributedElement}; elements that model complex parts of the classfile that
* themselves contain their own child elements will implement {@link
* CompoundElement}. Elements specific to various locations in the classfile
* will implement {@link ClassElement}, {@link MethodElement}, etc.
* Marker interface for structures with special capabilities in the {@code
* class} file format. {@link AttributedElement} indicates a structure has
* {@link Attribute}s. {@link CompoundElement} indicates a structure can be
* viewed as a composition of member structures, whose memberships are marked by
* {@link ClassElement}, {@link MethodElement}, {@link FieldElement}, or {@link
* CodeElement}.
*
* <h2 id="membership">Membership Elements</h2>
* {@link ClassModel}, {@link MethodModel}, {@link FieldModel}, and {@link
* CodeModel} each has a dedicated interface marking its member structures:
* {@link ClassElement}, {@link MethodElement}, {@link FieldElement}, and
* {@link CodeElement}. They can be supplied to a {@link ClassBuilder}, a
* {@link MethodBuilder}, a {@link FieldBuilder}, or a {@link CodeBuilder} to be
* included as members of the built model. Unless otherwise specified, these
* structures are delivered during the {@linkplain CompoundElement traversal} of
* the corresponding models. Some of these elements may appear at most once or
* exactly once in the traversal of the models; such elements have special
* treatment by {@link ClassFileBuilder} and are specified in their modeling
* interfaces. If such elements appear multiple times during traversal, the
* last occurrence should be used and all previous instances should be
* discarded.
* <p>
* These membership element marker interfaces are sealed; future versions of the
* Java SE Platform may define new elements to the sealed hierarchy when the
* {@code class} file format for the Java Platform evolves. Using an exhaustive
* pattern matching switch over these hierarchies indicates the user only wish
* the processing code to run on a specific version of Java Platform, and will
* fail if unknown new elements are encountered.
*
* @sealedGraph
* @since 24

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -25,44 +25,74 @@
package java.lang.classfile;
import java.lang.classfile.attribute.RuntimeVisibleAnnotationsAttribute;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
* A transformation on streams of elements. Transforms are used during
* transformation of classfile entities; a transform is provided to a method like
* {@link ClassFile#transformClass(ClassModel, ClassTransform)}, and the elements of the class,
* along with a builder, are presented to the transform.
*
* <p>The subtypes of {@linkplain
* ClassFileTransform} (e.g., {@link ClassTransform}) are functional interfaces
* that accept an element and a corresponding builder. Since any element can be
* reproduced on the builder via {@link ClassBuilder#with(ClassFileElement)}, a
* transform can easily leave elements in place, remove them, replace them, or
* augment them with other elements. This enables localized transforms to be
* represented concisely.
*
* <p>Transforms also have an {@link #atEnd(ClassFileBuilder)} method, for
* which the default implementation does nothing, so that a transform can
* perform additional building after the stream of elements is exhausted.
*
* <p>Transforms can be chained together via the {@link
* #andThen(ClassFileTransform)} method, so that the output of one becomes the
* input to another. This allows smaller units of transformation to be captured
* and reused.
*
* <p>Some transforms are stateful; for example, a transform that injects an
* annotation on a class may watch for the {@link RuntimeVisibleAnnotationsAttribute}
* element and transform it if found, but if it is not found, will generate a
* {@linkplain RuntimeVisibleAnnotationsAttribute} element containing the
* injected annotation from the {@linkplain #atEnd(ClassFileBuilder)} handler.
* To do this, the transform must accumulate some state during the traversal so
* that the end handler knows what to do. If such a transform is to be reused,
* its state must be reset for each traversal; this will happen automatically if
* the transform is created with {@link ClassTransform#ofStateful(Supplier)} (or
* corresponding methods for other classfile locations.)
* A transformation on a {@link CompoundElement} by processing its individual
* member elements and sending the results to a {@link ClassFileBuilder},
* through {@link ClassFileBuilder#transform}. A subtype of {@code
* ClassFileTransform} is defined for each subtype of {@link CompoundElement}
* and {@link ClassFileBuilder}, as shown in the sealed class hierarchy below.
* <p>
* For example, this is a basic transformation of a {@link CodeModel} that
* redirects all calls to static methods in the {@code Foo} class to the {@code
* Bar} class, preserving all other elements:
* {@snippet file="PackageSnippets.java" region=fooToBarTransform}
* Note that if no transformation of a member element is desired, the element
* should be presented to {@link ClassFileBuilder#with builder::with}. If no
* action is taken, that member element is dropped.
* <p>
* More advanced usages of transforms include {@linkplain ##start-end start or
* end handling}, {@linkplain ##stateful stateful transformation} that makes a
* decision based on previously encountered member elements, and {@linkplain
* ##composition composition} of transforms, where one transform processes the
* results of a previous transform on the input compound structure. All these
* capabilities are supported by this interface and accessible to user transform
* implementations.
* <p id="start-end">
* Users can define custom start and end handling for a transform by overriding
* {@link #atStart} and {@link #atEnd}. The start handler is called before any
* member element is processed, and the end handler is called after all member
* elements are processed. For example, the start handler can be used to inject
* extra code elements to the beginning of a code array, and the end handler,
* combined with stateful transformation, can perform cleanup actions, such as
* determining if an attribute has been merged, or if a new attribute should be
* defined. Each subtype of {@code ClassFileTransform} defines a utility method
* {@code endHandler} that returns a transform that only has end handling.
* <p id="stateful">
* Transforms can have states that persist across processing of individual
* member elements. For example, if a transform injects an annotation, the
* transform may keep track if it has encountered and presented an updated
* {@link RuntimeVisibleAnnotationsAttribute} to the builder; if it has not yet,
* it can present a new attribute containing only the injected annotation in its
* end handler. If such a transform is to be shared or reused, each returned
* transform should have its own state. Each subtype of {@code ClassFileTransform}
* defines a utility method {@code ofStateful} where a supplier creates the
* transform at its initial state each time the transform is reused.
* <p id="composition">
* Transforms can be composed via {@link #andThen}. When this transform is
* composed with another transform, it means the output member elements received
* by the {@link ClassFileBuilder} become the input elements to that other
* transform. Composition avoids building intermediate structures for multiple
* transforms to run on. Each subtype of {@code ClassFileTransform} implements
* {@link #andThen}, which generally should not be implemented by users.
* <p>
* Transforms that run on smaller structures can be lifted to its enclosing
* structures to selectively run on all enclosed smaller structures of the same
* kind. For example, a {@link CodeTransform} can be lifted via {@link
* ClassTransform#transformingMethodBodies(Predicate, CodeTransform)} to
* transform the method body of select methods in the class it runs on. This
* allows users to write small transforms and apply to larger scales.
* <p>
* Besides {@link ClassFileBuilder#transform}, there are other methods that
* accepts a transform conveniently, such as {@link ClassFile#transformClass},
* {@link ClassBuilder#transformField}, {@link ClassBuilder#transformMethod}, or
* {@link MethodBuilder#transformCode}. They are convenience methods that suit
* the majority of transformation scenarios.
*
* @param <C> the transform type
* @param <E> the element type
* @param <E> the member element type
* @param <B> the builder type
*
* @sealedGraph
@@ -79,6 +109,9 @@ public sealed interface ClassFileTransform<
* body.) If no transformation is desired, the element can be presented to
* {@link B#with(ClassFileElement)}. If the element is to be dropped, no
* action is required.
* <p>
* This method is called by the Class-File API. Users should never call
* this method.
*
* @param builder the builder for the new entity
* @param element the element
@@ -89,6 +122,9 @@ public sealed interface ClassFileTransform<
* Take any final action during transformation of a classfile entity. Called
* after all elements of the class are presented to {@link
* #accept(ClassFileBuilder, ClassFileElement)}.
* <p>
* This method is called by the Class-File API. Users should never call
* this method.
*
* @param builder the builder for the new entity
* @implSpec The default implementation does nothing.
@@ -100,6 +136,9 @@ public sealed interface ClassFileTransform<
* Take any preliminary action during transformation of a classfile entity.
* Called before any elements of the class are presented to {@link
* #accept(ClassFileBuilder, ClassFileElement)}.
* <p>
* This method is called by the Class-File API. Users should never call
* this method.
*
* @param builder the builder for the new entity
* @implSpec The default implementation does nothing.
@@ -110,6 +149,10 @@ public sealed interface ClassFileTransform<
/**
* Chain this transform with another; elements presented to the builder of
* this transform will become the input to the next transform.
* <p>
* This method is implemented by the Class-File API. Users usually don't
* have sufficient access to Class-File API functionalities to override this
* method correctly for generic downstream transforms.
*
* @param next the downstream transform
* @return the chained transform

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -24,32 +24,62 @@
*/
package java.lang.classfile;
import java.lang.reflect.ClassFileFormatVersion;
import jdk.internal.classfile.impl.ClassFileVersionImpl;
/**
* Models the classfile version information for a class. Delivered as a {@link
* java.lang.classfile.ClassElement} when traversing the elements of a {@link
* ClassModel}.
* Models the minor and major version numbers of a {@code class} file (JVMS
* {@jvms 4.1}). The {@code class} file version appears exactly once in each
* class, and is set to an unspecified default value if not explicitly provided.
* <p>
* The major versions of {@code class} file format begins at {@value
* ClassFile#JAVA_1_VERSION} for Java Platform version 1.0.2, and is continuous
* up to {@link ClassFile#latestMajorVersion()}. In general, each major version
* defines a new supported {@code class} file format, modeled by {@link
* ClassFileFormatVersion}, and supports all previous formats.
* <p>
* For major versions up to {@value ClassFile#JAVA_11_VERSION} for Java SE
* Platform 11, the minor version of any value is supported. For major versions
* {@value ClassFile#JAVA_12_VERSION} for Java SE Platform version 12 and above,
* the minor version must be {@code 0} or {@value ClassFile#PREVIEW_MINOR_VERSION}.
* The minor version {@code 0} is always supported, and represents the format
* modeled by {@link ClassFileFormatVersion}. The minor version {@code 65535}
* indicates the {@code class} file uses preview features of the Java SE
* Platform release represented by the major version. A Java Virtual Machine
* can only load such a {@code class} file if it has the same Java SE Platform
* version and the JVM has preview features enabled.
*
* @see ClassModel#majorVersion()
* @see ClassModel#minorVersion()
* @see ClassFileFormatVersion
* @jvms 4.1 The {@code ClassFile} Structure
* @since 24
*/
public sealed interface ClassFileVersion
extends ClassElement
permits ClassFileVersionImpl {
/**
* {@return the major classfile version}
* {@return the major version} It is in the range of unsigned short, {@code
* [0, 65535]}.
*
* @apiNote
* Constants in {@link ClassFile} named {@code Java_#_VERSION}, where # is
* a release number, such as {@link ClassFile#JAVA_21_VERSION}, describe the
* class major versions of the Java Platform SE.
*/
int majorVersion();
/**
* {@return the minor classfile version}
* {@return the minor version} It is in the range of unsigned short, {@code
* [0, 65535]}.
*/
int minorVersion();
/**
* {@return a {@link ClassFileVersion} element}
* @param majorVersion the major classfile version
* @param minorVersion the minor classfile version
* @param majorVersion the major version
* @param minorVersion the minor version
*/
static ClassFileVersion of(int majorVersion, int minorVersion) {
return new ClassFileVersionImpl(majorVersion, minorVersion);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -24,7 +24,11 @@
*/
package java.lang.classfile;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.lang.classfile.ClassFile.StackMapsOption;
import java.lang.classfile.attribute.StackMapTableAttribute;
import java.lang.constant.ClassDesc;
import java.lang.invoke.MethodHandles;
import java.util.Collection;
@@ -42,27 +46,42 @@ import static java.lang.constant.ConstantDescs.CD_Object;
import static java.util.Objects.requireNonNull;
/**
* Provides class hierarchy information for generating correct stack maps
* during code building.
* Provides class hierarchy information for {@linkplain StackMapsOption stack
* maps generation} and {@linkplain ClassFile#verify(byte[]) verification}.
* A class hierarchy resolver must be able to process all classes and interfaces
* encountered during these workloads.
*
* @see ClassFile.ClassHierarchyResolverOption
* @see StackMapTableAttribute
* @jvms 4.10.1.2 Verification Type System
* @since 24
*/
@FunctionalInterface
public interface ClassHierarchyResolver {
/**
* {@return the default instance of {@linkplain ClassHierarchyResolver} that
* {@return the default instance of {@code ClassHierarchyResolver} that
* gets {@link ClassHierarchyInfo} from system class loader with reflection}
* This default instance cannot load classes from other class loaders, such
* as the caller's class loader; it also loads the system classes if they
* are not yet loaded, which makes it unsuitable for instrumentation.
*/
static ClassHierarchyResolver defaultResolver() {
return ClassHierarchyImpl.DEFAULT_RESOLVER;
}
/**
* {@return the {@link ClassHierarchyInfo} for a given class name, or null
* if the name is unknown to the resolver}
* {@return the {@code ClassHierarchyInfo} for a given class name, or {@code
* null} if the name is unknown to the resolver}
* <p>
* This method is called by the Class-File API to obtain the hierarchy
* information of a class or interface; users should not call this method.
* The symbolic descriptor passed by the Class-File API always represents
* a class or interface.
*
* @param classDesc descriptor of the class
* @throws IllegalArgumentException if a class shouldn't be queried for hierarchy
* @throws IllegalArgumentException if a class shouldn't be queried for
* hierarchy, such as when it is inaccessible
*/
ClassHierarchyInfo getClassInfo(ClassDesc classDesc);
@@ -78,6 +97,7 @@ public interface ClassHierarchyResolver {
*
* @param superClass descriptor of the super class, may be {@code null}
* @return the info indicating the super class
* @see Superclass
*/
static ClassHierarchyInfo ofClass(ClassDesc superClass) {
return new ClassHierarchyImpl.ClassHierarchyInfoImpl(superClass, false);
@@ -94,14 +114,15 @@ public interface ClassHierarchyResolver {
}
/**
* Chains this {@linkplain ClassHierarchyResolver} with another to be
* consulted if this resolver does not know about the specified class.
* Chains this {@code ClassHierarchyResolver} with another to be consulted
* if this resolver does not know about the specified class.
*
* @implSpec
* The default implementation returns resolver implemented to query {@code
* other} resolver in case this resolver returns {@code null}.
*
* @param other the other resolver
* @return the chained resolver
*
* @implSpec The default implementation returns resolver implemented to ask
* other resolver in cases where this resolver returns {@code null}.
*/
default ClassHierarchyResolver orElse(ClassHierarchyResolver other) {
requireNonNull(other);
@@ -117,32 +138,32 @@ public interface ClassHierarchyResolver {
}
/**
* Returns a ClassHierarchyResolver that caches class hierarchy information from this
* resolver. The returned resolver will not update if delegate resolver returns differently.
* The thread safety of the returned resolver depends on the thread safety of the map
* {@return a {@code ClassHierarchyResolver} that caches class hierarchy
* information from this resolver} The returned resolver will not update if
* the query results from this resolver changed over time. The thread
* safety of the returned resolver depends on the thread safety of the map
* returned by the {@code cacheFactory}.
*
* @param cacheFactory the factory for the cache
* @return the ClassHierarchyResolver with caching
* @implSpec
* The default implementation returns a resolver holding an instance of the
* cache map provided by the {@code cacheFactory}. It looks up in the cache
* map, or if a class name has not yet been queried, queries this resolver
* and caches the result, including a {@code null} that indicates unknown
* class names. The cache map may refuse {@code null} keys and values.
*
* @implSpec The default implementation returns resolver holding an instance
* of the cache map provided by the {@code cacheFactory}. It asks
* the cache map always first and fills the cache map with all
* resolved and also unresolved class info. The cache map may refuse
* {@code null} keys and values.
* @param cacheFactory the factory for the cache
*/
default ClassHierarchyResolver cached(Supplier<Map<ClassDesc, ClassHierarchyInfo>> cacheFactory) {
return new ClassHierarchyImpl.CachedClassHierarchyResolver(this, cacheFactory.get());
}
/**
* Returns a ClassHierarchyResolver that caches class hierarchy information from this
* resolver. The returned resolver will not update if delegate resolver returns differently.
* The returned resolver is not thread-safe.
* {@return a {@code ClassHierarchyResolver} that caches class hierarchy
* information from this resolver} The returned resolver will not update if
* the query results from this resolver changed over time. The returned
* resolver is not thread-safe.
* {@snippet file="PackageSnippets.java" region="lookup-class-hierarchy-resolver"}
*
* @return the ClassHierarchyResolver
*
* @implSpec The default implementation calls {@link #cached(Supplier)} with
* {@link HashMap} supplier as {@code cacheFactory}.
*/
@@ -160,24 +181,24 @@ public interface ClassHierarchyResolver {
}
/**
* Returns a {@linkplain ClassHierarchyResolver} that extracts class hierarchy
* information from classfiles located by a mapping function. The mapping function
* should return null if it cannot provide a mapping for a classfile. Any IOException
* from the provided input stream is rethrown as an UncheckedIOException.
* {@return a {@code ClassHierarchyResolver} that extracts class hierarchy
* information from {@code class} files returned by a mapping function} The
* mapping function should return {@code null} if it cannot provide a
* {@code class} file for a class name. Any {@link IOException} from the
* provided input stream is rethrown as an {@link UncheckedIOException}
* in {@link #getClassInfo(ClassDesc)}.
*
* @param classStreamResolver maps class descriptors to classfile input streams
* @return the {@linkplain ClassHierarchyResolver}
* @param classStreamResolver maps class descriptors to {@code class} file input streams
*/
static ClassHierarchyResolver ofResourceParsing(Function<ClassDesc, InputStream> classStreamResolver) {
return new ClassHierarchyImpl.ResourceParsingClassHierarchyResolver(requireNonNull(classStreamResolver));
}
/**
* Returns a {@linkplain ClassHierarchyResolver} that extracts class hierarchy
* information from classfiles located by a class loader.
* {@return a {@code ClassHierarchyResolver} that extracts class hierarchy
* information from {@code class} files located by a class loader}
*
* @param loader the class loader, to find class files
* @return the {@linkplain ClassHierarchyResolver}
*/
static ClassHierarchyResolver ofResourceParsing(ClassLoader loader) {
requireNonNull(loader);
@@ -190,24 +211,22 @@ public interface ClassHierarchyResolver {
}
/**
* Returns a {@linkplain ClassHierarchyResolver} that extracts class hierarchy
* information from collections of class hierarchy metadata
* {@return a {@code ClassHierarchyResolver} that extracts class hierarchy
* information from collections of class hierarchy metadata}
*
* @param interfaces a collection of classes known to be interfaces
* @param classToSuperClass a map from classes to their super classes
* @return the {@linkplain ClassHierarchyResolver}
*/
static ClassHierarchyResolver of(Collection<ClassDesc> interfaces,
Map<ClassDesc, ClassDesc> classToSuperClass) {
Map<ClassDesc, ClassDesc> classToSuperClass) {
return new StaticClassHierarchyResolver(interfaces, classToSuperClass);
}
/**
* Returns a ClassHierarchyResolver that extracts class hierarchy information via
* the Reflection API with a {@linkplain ClassLoader}.
* {@return a {@code ClassHierarchyResolver} that extracts class hierarchy
* information via classes loaded by a class loader with reflection}
*
* @param loader the class loader
* @return the class hierarchy resolver
*/
static ClassHierarchyResolver ofClassLoading(ClassLoader loader) {
requireNonNull(loader);
@@ -224,13 +243,13 @@ public interface ClassHierarchyResolver {
}
/**
* Returns a ClassHierarchyResolver that extracts class hierarchy information via
* the Reflection API with a {@linkplain MethodHandles.Lookup Lookup}. If the class
* resolved is inaccessible to the given lookup, it throws {@link
* {@return a {@code ClassHierarchyResolver} that extracts class hierarchy
* information via classes accessible to a {@link MethodHandles.Lookup}
* with reflection} If the class resolved is inaccessible to the given
* lookup, {@link #getClassInfo(ClassDesc)} throws {@link
* IllegalArgumentException} instead of returning {@code null}.
*
* @param lookup the lookup, must be able to access classes to resolve
* @return the class hierarchy resolver
*/
static ClassHierarchyResolver ofClassLoading(MethodHandles.Lookup lookup) {
requireNonNull(lookup);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -25,18 +25,41 @@
package java.lang.classfile;
import java.lang.classfile.attribute.BootstrapMethodsAttribute;
import java.lang.classfile.attribute.ModuleAttribute;
import java.lang.classfile.constantpool.ClassEntry;
import java.lang.classfile.constantpool.ConstantPool;
import java.lang.classfile.constantpool.ConstantPoolBuilder;
import java.lang.constant.ClassDesc;
import java.lang.reflect.AccessFlag;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import jdk.internal.classfile.impl.ClassImpl;
/**
* Models a classfile. The contents of the classfile can be traversed via
* a streaming view, or via random access (e.g.,
* {@link #flags()}), or by freely mixing the two.
* Models a {@code class} file. A {@code class} file can be viewed as a
* {@linkplain CompoundElement composition} of {@link ClassElement}s, or by
* random access via accessor methods if only specific parts of the {@code
* class} file is needed.
* <p>
* Use {@link ClassFile#parse(byte[])}, which parses the binary data of a {@code
* class} file into a model, to obtain a {@code ClassModel}.
* <p>
* To construct a {@code class} file, use {@link ClassFile#build(ClassDesc,
* Consumer)}. {@link ClassFile#transformClass(ClassModel, ClassTransform)}
* allows creating a new class by selectively processing the original class
* elements and directing the results to a class builder.
* <p>
* A class holds attributes, most of which are accessible as member elements.
* {@link BootstrapMethodsAttribute} can only be accessed via {@linkplain
* AttributedElement explicit attribute reading}, as it is modeled as part of
* the {@linkplain #constantPool() constant pool}.
*
* @see ClassFile#parse(byte[])
* @see ClassTransform
* @jvms 4.1 The {@code ClassFile} Structure
* @since 24
*/
public sealed interface ClassModel
@@ -45,19 +68,35 @@ public sealed interface ClassModel
/**
* {@return the constant pool for this class}
*
* @see ConstantPoolBuilder#of(ClassModel)
*/
ConstantPool constantPool();
/** {@return the access flags} */
/**
* {@return the access flags}
*
* @see AccessFlag.Location#CLASS
*/
AccessFlags flags();
/** {@return the constant pool entry describing the name of this class} */
ClassEntry thisClass();
/** {@return the major classfile version} */
/**
* {@return the major version of this class} It is in the range of unsigned
* short, {@code [0, 65535]}.
*
* @see ClassFileVersion
*/
int majorVersion();
/** {@return the minor classfile version} */
/**
* {@return the minor version of this class} It is in the range of unsigned
* short, {@code [0, 65535]}.
*
* @see ClassFileVersion
*/
int minorVersion();
/** {@return the fields of this class} */
@@ -66,12 +105,28 @@ public sealed interface ClassModel
/** {@return the methods of this class} */
List<MethodModel> methods();
/** {@return the superclass of this class, if there is one} */
/**
* {@return the superclass of this class, if there is one}
* This {@code class} file may have no superclass if this represents a
* {@linkplain #isModuleInfo() module descriptor} or the {@link Object}
* class; otherwise, it must have a superclass. If this is an interface,
* the superclass must be {@link Object}.
*
* @see Superclass
*/
Optional<ClassEntry> superclass();
/** {@return the interfaces implemented by this class} */
/**
* {@return the interfaces implemented by this class}
*
* @see Interfaces
*/
List<ClassEntry> interfaces();
/** {@return whether this class is a module descriptor} */
/**
* {@return whether this {@code class} file is a module descriptor}
*
* @see ClassFile#buildModule(ModuleAttribute, Consumer)
*/
boolean isModuleInfo();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -35,12 +35,21 @@ import java.util.function.Function;
import jdk.internal.classfile.impl.ClassReaderImpl;
/**
* Supports reading from a classfile. Methods are provided to read data of
* various numeric types (e.g., {@code u2}, {@code u4}) at a given offset within
* the classfile, copying raw bytes, and reading constant pool entries.
* Encapsulates additional reading context such as mappers for custom attributes
* and processing options.
* Advanced {@code class} file reading support for {@link AttributeMapper}s.
* Supports reading arbitrary offsets within a {@code class} file and reading
* data of various numeric types (e.g., {@code u2}, {@code u4}) in addition to
* constant pool access.
* <p>
* All numeric values in the {@code class} file format are {@linkplain
* java.nio.ByteOrder#BIG_ENDIAN big endian}.
* <p>
* Unless otherwise specified, all out-of-bounds access result in an {@link
* IllegalArgumentException} to indicate the {@code class} file data is
* malformed. Since the {@code class} file data is arbitrary, users should
* sanity-check the structural integrity of the data before attempting to
* interpret the potentially malformed data.
*
* @see AttributeMapper#readAttribute(AttributedElement, ClassReader, int)
* @since 24
*/
public sealed interface ClassReader extends ConstantPool
@@ -56,29 +65,41 @@ public sealed interface ClassReader extends ConstantPool
// Class context
/** {@return the access flags for the class, as a bit mask } */
/**
* {@return the access flags for the class, as a bit mask}
*
* @see ClassModel#flags()
*/
int flags();
/** {@return the constant pool entry describing the name of class} */
/**
* {@return the constant pool entry describing the name of class}
*
* @see ClassModel#thisClass()
*/
ClassEntry thisClassEntry();
/** {@return the constant pool entry describing the name of the superclass, if any} */
/**
* {@return the constant pool entry describing the name of the superclass, if any}
*
* @see ClassModel#superclass()
*/
Optional<ClassEntry> superclassEntry();
/** {@return the length of the classfile, in bytes} */
/** {@return the length of the {@code class} file, in number of bytes} */
int classfileLength();
// Constant pool
/**
* {@return the constant pool entry whose index is given at the specified
* offset within the classfile}
* offset within the {@code class} file}
*
* @apiNote
* If only a particular type of entry is expected, use {@link #readEntry(
* int, Class) readEntry(int, Class)}.
*
* @param offset the offset of the index within the classfile
* @param offset the offset of the index within the {@code class} file
* @throws ConstantPoolException if the index is out of range of the
* constant pool size, or zero
*/
@@ -86,9 +107,9 @@ public sealed interface ClassReader extends ConstantPool
/**
* {@return the constant pool entry of a given type whose index is given
* at the specified offset within the classfile}
* at the specified offset within the {@code class} file}
* @param <T> the entry type
* @param offset the offset of the index within the classfile
* @param offset the offset of the index within the {@code class} file
* @param cls the entry type
* @throws ConstantPoolException if the index is out of range of the
* constant pool size, or zero, or the entry is not of the given type
@@ -97,14 +118,14 @@ public sealed interface ClassReader extends ConstantPool
/**
* {@return the constant pool entry whose index is given at the specified
* offset within the classfile, or null if the index at the specified
* offset is zero}
* offset within the {@code class} file, or {@code null} if the index at the
* specified offset is zero}
*
* @apiNote
* If only a particular type of entry is expected, use {@link #readEntryOrNull(
* int, Class) readEntryOrNull(int, Class)}.
*
* @param offset the offset of the index within the classfile
* @param offset the offset of the index within the {@code class} file
* @throws ConstantPoolException if the index is out of range of the
* constant pool size
*/
@@ -112,11 +133,11 @@ public sealed interface ClassReader extends ConstantPool
/**
* {@return the constant pool entry of a given type whose index is given
* at the specified offset within the classfile, or null if the index at
* the specified offset is zero}
* at the specified offset within the {@code class} file, or {@code null} if
* the index at the specified offset is zero}
*
* @param <T> the entry type
* @param offset the offset of the index within the classfile
* @param offset the offset of the index within the {@code class} file
* @param cls the entry type
* @throws ConstantPoolException if the index is out of range of the
* constant pool size, or zero, or the entry is not of the given type
@@ -124,65 +145,89 @@ public sealed interface ClassReader extends ConstantPool
<T extends PoolEntry> T readEntryOrNull(int offset, Class<T> cls);
/**
* {@return the unsigned byte at the specified offset within the classfile}
* @param offset the offset within the classfile
* {@return the unsigned byte at the specified offset within the {@code
* class} file} Reads a byte and zero-extends it to an {@code int}.
*
* @param offset the offset within the {@code class} file
*/
int readU1(int offset);
/**
* {@return the unsigned short at the specified offset within the classfile}
* @param offset the offset within the classfile
* {@return the unsigned short at the specified offset within the {@code
* class} file} Reads a 2-byte value and zero-extends it to an {@code int}.
*
* @param offset the offset within the {@code class} file
*/
int readU2(int offset);
/**
* {@return the signed byte at the specified offset within the classfile}
* @param offset the offset within the classfile
* {@return the signed byte at the specified offset within the {@code class}
* file} Reads a byte and sign-extends it to an {@code int}.
*
* @param offset the offset within the {@code class} file
*/
int readS1(int offset);
/**
* {@return the signed byte at the specified offset within the classfile}
* @param offset the offset within the classfile
* {@return the signed byte at the specified offset within the {@code class}
* file} Reads a 2-byte value and sign-extends it to an {@code int}.
*
* @param offset the offset within the {@code class} file
*/
int readS2(int offset);
/**
* {@return the signed int at the specified offset within the classfile}
* @param offset the offset within the classfile
* {@return the signed int at the specified offset within the {@code class}
* file} Reads 4 bytes of value.
*
* @param offset the offset within the {@code class} file
*/
int readInt(int offset);
/**
* {@return the signed long at the specified offset within the classfile}
* @param offset the offset within the classfile
* {@return the signed long at the specified offset within the {@code class}
* file} Reads 8 bytes of value.
*
* @param offset the offset within the {@code class} file
*/
long readLong(int offset);
/**
* {@return the float value at the specified offset within the classfile}
* @param offset the offset within the classfile
* {@return the float value at the specified offset within the {@code class}
* file} Reads 4 bytes of value.
* <p>
* In the conversions, all NaN values of the {@code float} may or may not be
* collapsed into a single {@linkplain Float#NaN "canonical" NaN value}.
*
* @param offset the offset within the {@code class} file
*/
float readFloat(int offset);
/**
* {@return the double value at the specified offset within the classfile}
* @param offset the offset within the classfile
* {@return the double value at the specified offset within the {@code
* class} file} Reads 8 bytes of value.
* <p>
* In the conversions, all NaN values of the {@code double} may or may not
* be collapsed into a single {@linkplain Double#NaN "canonical" NaN value}.
*
* @param offset the offset within the {@code class} file
*/
double readDouble(int offset);
/**
* {@return a copy of the bytes at the specified range in the classfile}
* @param offset the offset within the classfile
* {@return a copy of the bytes at the specified range in the {@code class}
* file}
*
* @param offset the offset within the {@code class} file
* @param len the length of the range
*/
byte[] readBytes(int offset, int len);
/**
* Copy a range of bytes from the classfile to a {@link BufWriter}
* Copy a range of bytes from the {@code class} file to a {@link BufWriter}.
*
* @param buf the {@linkplain BufWriter}
* @param offset the offset within the classfile
* @param offset the offset within the {@code class} file
* @param len the length of the range
*/
void copyBytesTo(BufWriter buf, int offset, int len);

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -24,6 +24,7 @@
*/
package java.lang.classfile;
import java.lang.classfile.attribute.SignatureAttribute;
import java.util.List;
import jdk.internal.classfile.impl.SignaturesImpl;
@@ -31,27 +32,53 @@ import jdk.internal.classfile.impl.SignaturesImpl;
import static java.util.Objects.requireNonNull;
/**
* Models the generic signature of a class file, as defined by JVMS {@jvms 4.7.9}.
* Models the generic signature of a class or interface, as defined by JVMS
* {@jvms 4.7.9.1}.
*
* @see Class
* @see SignatureAttribute
* @jls 8.1 Class Declarations
* @jls 9.1 Interface Declarations
* @jvms 4.7.9.1 Signatures
* @since 24
*/
public sealed interface ClassSignature
permits SignaturesImpl.ClassSignatureImpl {
/** {@return the type parameters of this class} */
/**
* {@return the type parameters of this class or interface, may be empty}
*
* @see Class#getTypeParameters()
* @jls 8.1.2 Generic Classes and Type Parameters
* @jls 9.1.2 Generic Interfaces and Type Parameters
*/
List<Signature.TypeParam> typeParameters();
/** {@return the instantiation of the superclass in this signature} */
/**
* {@return the instantiation of the superclass in this signature}
* Interfaces return a signature representing the {@link Object} class.
*
* @see Class#getGenericSuperclass()
* @jls 8.1.4 Superclasses and Subclasses
*/
Signature.ClassTypeSig superclassSignature();
/** {@return the instantiation of the interfaces in this signature} */
/**
* {@return the instantiation of the interfaces in this signature, may be
* empty}
*
* @see Class#getGenericInterfaces()
* @jls 8.1.5 Superinterfaces
* @jls 9.1.3 Superinterfaces and Subinterfaces
*/
List<Signature.ClassTypeSig> superinterfaceSignatures();
/** {@return the raw signature string} */
String signatureString();
/**
* {@return a class signature}
* {@return a class signature with no type parameter declaration}
*
* @param superclassSignature the superclass
* @param superinterfaceSignatures the interfaces
*/
@@ -62,7 +89,7 @@ public sealed interface ClassSignature
/**
* {@return a class signature}
* @param typeParameters the type parameters
* @param typeParameters the type parameters, may be empty
* @param superclassSignature the superclass
* @param superinterfaceSignatures the interfaces
*/
@@ -76,9 +103,11 @@ public sealed interface ClassSignature
}
/**
* Parses a raw class signature string into a {@linkplain Signature}
* Parses a raw class signature string into a {@linkplain Signature}.
*
* @param classSignature the raw class signature string
* @return class signature
* @throws IllegalArgumentException if the string is not a valid class signature string
*/
public static ClassSignature parseFrom(String classSignature) {
return new SignaturesImpl(classSignature).parseClassSignature();

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -35,9 +35,12 @@ import static java.util.Objects.requireNonNull;
/**
* A transformation on streams of {@link ClassElement}.
* <p>
* Refer to {@link ClassFileTransform} for general guidance and caution around
* the use of transforms for structures in the {@code class} file format.
*
* @see ClassFileTransform
*
* @see ClassModel
* @see ClassFile#transformClass(ClassModel, ClassTransform)
* @since 24
*/
@FunctionalInterface
@@ -45,7 +48,7 @@ public non-sealed interface ClassTransform
extends ClassFileTransform<ClassTransform, ClassElement, ClassBuilder> {
/**
* A class transform that sends all elements to the builder.
* A class transform that passes all elements to the builder.
*/
static final ClassTransform ACCEPT_ALL = new ClassTransform() {
@Override
@@ -55,7 +58,7 @@ public non-sealed interface ClassTransform
};
/**
* Create a stateful class transform from a {@link Supplier}. The supplier
* Creates a stateful class transform from a {@link Supplier}. The supplier
* will be invoked for each transformation.
*
* @param supplier a {@link Supplier} that produces a fresh transform object
@@ -67,7 +70,7 @@ public non-sealed interface ClassTransform
}
/**
* Create a class transform that passes each element through to the builder,
* Creates a class transform that passes each element through to the builder,
* and calls the specified function when transformation is complete.
*
* @param finisher the function to call when transformation is complete
@@ -89,8 +92,8 @@ public non-sealed interface ClassTransform
}
/**
* Create a class transform that passes each element through to the builder,
* except for those that the supplied {@link Predicate} is true for.
* Creates a class transform that passes each element through to the builder,
* except for those that the supplied {@link Predicate} returns true for.
*
* @param filter the predicate that determines which elements to drop
* @return the class transform
@@ -104,8 +107,10 @@ public non-sealed interface ClassTransform
}
/**
* Create a class transform that transforms {@link MethodModel} elements
* with the supplied method transform.
* Creates a class transform that transforms {@link MethodModel} elements
* with the supplied method transform for methods that the supplied {@link
* Predicate} returns true for, passing other elements through to the
* builder.
*
* @param filter a predicate that determines which methods to transform
* @param xform the method transform
@@ -117,8 +122,9 @@ public non-sealed interface ClassTransform
}
/**
* Create a class transform that transforms {@link MethodModel} elements
* with the supplied method transform.
* Creates a class transform that transforms {@link MethodModel} elements
* with the supplied method transform, passing other elements through to the
* builder.
*
* @param xform the method transform
* @return the class transform
@@ -128,8 +134,10 @@ public non-sealed interface ClassTransform
}
/**
* Create a class transform that transforms the {@link CodeAttribute} (method body)
* of {@link MethodModel} elements with the supplied code transform.
* Creates a class transform that transforms the {@link CodeAttribute} (method body)
* of {@link MethodModel} elements with the supplied code transform for
* methods that the supplied {@link Predicate} returns true for, passing
* other elements through to the builder.
*
* @param filter a predicate that determines which methods to transform
* @param xform the code transform
@@ -141,8 +149,9 @@ public non-sealed interface ClassTransform
}
/**
* Create a class transform that transforms the {@link CodeAttribute} (method body)
* of {@link MethodModel} elements with the supplied code transform.
* Creates a class transform that transforms the {@link CodeAttribute} (method body)
* of {@link MethodModel} elements with the supplied code transform, passing
* other elements through to the builder.
*
* @param xform the code transform
* @return the class transform
@@ -152,8 +161,9 @@ public non-sealed interface ClassTransform
}
/**
* Create a class transform that transforms {@link FieldModel} elements
* with the supplied field transform.
* Creates a class transform that transforms {@link FieldModel} elements
* with the supplied field transform, passing other elements through to the
* builder.
*
* @param xform the field transform
* @return the class transform

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -29,13 +29,20 @@ import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute;
import java.lang.classfile.attribute.StackMapTableAttribute;
/**
* A marker interface for elements that can appear when traversing
* a {@link CodeModel} or be presented to a {@link CodeBuilder}. Code elements
* are either an {@link Instruction}, which models an instruction in the body
* of a method, or a {@link PseudoInstruction}, which models metadata from
* the code attribute, such as line number metadata, local variable metadata,
* exception metadata, label target metadata, etc.
* Marker interface for a member element of a {@link CodeModel}. Such an
* element can appear when traversing a {@link CodeModel} unless otherwise
* specified, be supplied to a {@link CodeBuilder}, and be processed by a
* {@link CodeTransform}.
* <p>
* Code elements can be categorized into {@link Instruction}, {@link
* PseudoInstruction}, and {@link Attribute}. Unlike in other {@link
* CompoundElement}, the order of elements for all {@link Instruction}s and some
* {@link PseudoInstruction}s is significant.
*
* @see ClassFileElement##membership Membership Elements
* @see ClassElement
* @see MethodElement
* @see FieldElement
* @sealedGraph
* @since 24
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -25,17 +25,44 @@
package java.lang.classfile;
import java.lang.classfile.ClassFile.DeadLabelsOption;
import java.lang.classfile.ClassFile.DebugElementsOption;
import java.lang.classfile.ClassFile.LineNumbersOption;
import java.lang.classfile.attribute.BootstrapMethodsAttribute;
import java.lang.classfile.attribute.CodeAttribute;
import java.lang.classfile.attribute.StackMapTableAttribute;
import java.lang.classfile.instruction.ExceptionCatch;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import jdk.internal.classfile.impl.BufferedCodeBuilder;
/**
* Models the body of a method (the {@code Code} attribute). The instructions
* of the method body are accessed via a streaming view.
* Models the body of a method (the {@code Code} attribute). A {@code Code}
* attribute is viewed as a {@linkplain CompoundElement composition} of {@link
* CodeElement}s, which is the only way to access {@link Instruction}s; the
* order of elements of a code model is significant.
* <p>
* A {@code CodeModel} is obtained from {@link MethodModel#code()}, or in the
* traversal of the member elements of a method.
* <p>
* {@link MethodBuilder#withCode} is the main way to build code models. {@link
* MethodBuilder#transformCode} and {@link CodeBuilder#transforming} allow
* creating new {@code Code} attributes by selectively processing the original
* code elements and directing the results to a code builder.
* <p>
* A {@code Code} attribute holds attributes, but they are usually not member
* elements, but are decomposed to {@link PseudoInstruction}, accessible
* according to {@link DeadLabelsOption}, {@link DebugElementsOption}, and
* {@link LineNumbersOption}. {@link StackMapTableAttribute} can only be
* accessed via {@linkplain AttributedElement explicit attribute reading}, as it
* is considered a derived property from the code body.
*
* @see MethodModel#code()
* @see CodeTransform
* @see CodeAttribute
* @jvms 4.7.3 The {@code Code} Attribute
* @since 24
*/
public sealed interface CodeModel

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -32,10 +32,22 @@ import jdk.internal.classfile.impl.TransformImpl;
import static java.util.Objects.requireNonNull;
/**
* A transformation on streams of {@link CodeElement}.
*
* @see ClassFileTransform
* A transformation on streams of {@link CodeElement}. The stream can come
* from a {@link CodeModel}, or a handler to a {@link CodeBuilder} as in
* {@link CodeBuilder#transforming}.
* <p>
* Refer to {@link ClassFileTransform} for general guidance and caution around
* the use of transforms for structures in the {@code class} file format.
* <p>
* A code transform can be lifted to a method or a class transform via {@link
* MethodTransform#transformingCode(CodeTransform)} and {@link
* ClassTransform#transformingMethodBodies(CodeTransform)}, transforming only
* the {@link CodeModel} within those structures and passing all other elements
* to the builders.
*
* @see CodeModel
* @see MethodBuilder#transformCode
* @see CodeBuilder#transforming
* @since 24
*/
@FunctionalInterface
@@ -43,7 +55,7 @@ public non-sealed interface CodeTransform
extends ClassFileTransform<CodeTransform, CodeElement, CodeBuilder> {
/**
* A code transform that sends all elements to the builder.
* A code transform that passes all elements to the builder.
*/
CodeTransform ACCEPT_ALL = new CodeTransform() {
@Override
@@ -53,7 +65,7 @@ public non-sealed interface CodeTransform
};
/**
* Create a stateful code transform from a {@link Supplier}. The supplier
* Creates a stateful code transform from a {@link Supplier}. The supplier
* will be invoked for each transformation.
*
* @param supplier a {@link Supplier} that produces a fresh transform object
@@ -65,7 +77,7 @@ public non-sealed interface CodeTransform
}
/**
* Create a code transform that passes each element through to the builder,
* Creates a code transform that passes each element through to the builder,
* and calls the specified function when transformation is complete.
*
* @param finisher the function to call when transformation is complete

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -34,15 +34,29 @@ import java.util.function.Consumer;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.classfile.components.ClassPrinter;
/**
* A {@link ClassFileElement} that has complex structure defined in terms of
* other classfile elements, such as a method, field, method body, or entire
* class. When encountering a {@linkplain CompoundElement}, clients have the
* option to treat the element as a single entity (e.g., an entire method)
* or to traverse the contents of that element with the methods in this class
* (e.g., {@link #forEach(Consumer)}, etc.)
* @param <E> the element type
* A {@code class} file structure that can be viewed as a composition of its
* member structures. {@code CompoundElement} allows users to traverse these
* member elements with {@link #forEach(Consumer)} or {@link #elementStream()},
* or buffer the elements obtained from the traversal through {@link
* #iterator()} or {@link #elementList()}.
* <p>
* Unless otherwise specified, all member elements of compatible type will be
* presented during the traversal if they exist in this element. Some member
* elements specify that they may appear at most once in this element; if such
* elements are presented multiple times, the latest occurrence is authentic and
* all previous occurrences should be ignored.
* <p>
* {@code CompoundElement}s can be constructed by {@link ClassFileBuilder}s.
* {@link ClassFileBuilder#transform(CompoundElement, ClassFileTransform)}
* provides an easy way to create a new structure by selectively processing
* the original member structures and directing the results to the builder.
*
* @param <E> the member element type
* @see ClassFileElement##membership Membership Elements
* @see ClassFileBuilder
* @sealedGraph
* @since 24
*/
@@ -50,15 +64,16 @@ public sealed interface CompoundElement<E extends ClassFileElement>
extends ClassFileElement, Iterable<E>
permits ClassModel, CodeModel, FieldModel, MethodModel, jdk.internal.classfile.impl.AbstractUnboundModel {
/**
* Invoke the provided handler with each element contained in this
* compound element
* Invokes the provided handler with each member element in this compound
* element.
*
* @param consumer the handler
*/
@Override
void forEach(Consumer<? super E> consumer);
/**
* {@return an {@link Iterator} describing all the elements contained in this
* {@return an {@link Iterator} describing all member elements in this
* compound element}
*/
@Override
@@ -67,8 +82,8 @@ public sealed interface CompoundElement<E extends ClassFileElement>
}
/**
* {@return a {@link Stream} containing all the elements contained in this
* compound element}
* {@return a {@link Stream} containing all member elements in this compound
* element}
*/
default Stream<E> elementStream() {
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
@@ -78,8 +93,8 @@ public sealed interface CompoundElement<E extends ClassFileElement>
}
/**
* {@return an {@link List} containing all the elements contained in this
* compound element}
* {@return a {@link List} containing all member elements in this compound
* element}
*/
default List<E> elementList() {
List<E> list = new ArrayList<>();
@@ -92,4 +107,16 @@ public sealed interface CompoundElement<E extends ClassFileElement>
return Collections.unmodifiableList(list);
}
/**
* {@return a text representation of the compound element and its contents
* for debugging purposes}
*
* The format, structure and exact contents of the returned string are not
* specified and may change at any time in the future.
*/
default String toDebugString() {
StringBuilder text = new StringBuilder();
ClassPrinter.toYaml(this, ClassPrinter.Verbosity.TRACE_ALL, text::append);
return text.toString();
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -24,16 +24,28 @@
*/
package java.lang.classfile;
import java.lang.classfile.constantpool.PoolEntry;
import java.lang.classfile.constantpool.Utf8Entry;
import jdk.internal.classfile.impl.TemporaryConstantPool;
/**
* Models a non-standard attribute of a classfile. Clients should extend
* this class to provide an implementation class for non-standard attributes,
* and provide an {@link AttributeMapper} to mediate between the classfile
* format and the {@linkplain CustomAttribute} representation.
* @param <T> the custom attribute type
* Models a user-defined attribute in a {@code class} file. API models for
* user-defined attributes should extend this class. A user-defined attribute
* should also have an {@link AttributeMapper} defined, which will be returned
* by {@link #attributeMapper}, and registered to the {@link
* ClassFile.AttributeMapperOption} so the user-defined attributes can be read.
* <p>
* User-defined attributes are currently not delivered in the traversal of a
* {@link CodeModel}.
* <p>
* Accessor methods on user-defined attributes read from {@code class} files
* may throw {@link IllegalArgumentException} if the attribute model is lazily
* evaluated, and the evaluation encounters malformed {@code class} file format
* for the attribute.
*
* @param <T> the custom attribute type
* @see java.lang.classfile.attribute
* @since 24
*/
public abstract non-sealed class CustomAttribute<T extends CustomAttribute<T>>
@@ -42,7 +54,8 @@ public abstract non-sealed class CustomAttribute<T extends CustomAttribute<T>>
private final AttributeMapper<T> mapper;
/**
* Construct a {@linkplain CustomAttribute}.
* Constructor for subclasses to call.
*
* @param mapper the attribute mapper
*/
protected CustomAttribute(AttributeMapper<T> mapper) {
@@ -54,6 +67,17 @@ public abstract non-sealed class CustomAttribute<T extends CustomAttribute<T>>
return mapper;
}
/**
* {@inheritDoc}
*
* @implSpec
* The default implementation returns a {@code Utf8Entry} suitable for
* writing only, which may be {@linkplain PoolEntry##unbound unbound}.
* Subclasses representing attributes read from {@code class} files must
* override this method.
*
* @see AttributeMapper#readAttribute
*/
@Override
public Utf8Entry attributeName() {
return TemporaryConstantPool.INSTANCE.utf8Entry(mapper.name());

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -25,7 +25,7 @@
package java.lang.classfile;
import java.lang.classfile.constantpool.Utf8Entry;
import java.lang.constant.ClassDesc;
import java.lang.reflect.AccessFlag;
import java.util.function.Consumer;
@@ -34,14 +34,17 @@ import jdk.internal.classfile.impl.ChainedFieldBuilder;
import jdk.internal.classfile.impl.TerminalFieldBuilder;
/**
* A builder for fields. Builders are not created directly; they are passed
* to handlers by methods such as {@link ClassBuilder#withField(Utf8Entry, Utf8Entry, Consumer)}
* or to field transforms. The elements of a field can be specified
* abstractly (by passing a {@link FieldElement} to {@link #with(ClassFileElement)}
* or concretely by calling the various {@code withXxx} methods.
* A builder for fields. The main way to obtain a field builder is via {@link
* ClassBuilder#withField(String, ClassDesc, Consumer)}. The {@linkplain
* ClassBuilder#withField(String, ClassDesc, int) access flag overload} is
* useful if no attribute needs to be configured, skipping the handler.
* <p>
* Refer to {@link ClassFileBuilder} for general guidance and caution around
* the use of builders for structures in the {@code class} file format.
*
* @see ClassBuilder#withField(String, ClassDesc, Consumer)
* @see FieldModel
* @see FieldTransform
*
* @since 24
*/
public sealed interface FieldBuilder
@@ -50,8 +53,12 @@ public sealed interface FieldBuilder
/**
* Sets the field access flags.
*
* @param flags the access flags, as a bit mask
* @return this builder
* @see AccessFlags
* @see AccessFlag.Location#FIELD
* @see ClassBuilder#withField(String, ClassDesc, int)
*/
default FieldBuilder withFlags(int flags) {
return with(new AccessFlagsImpl(AccessFlag.Location.FIELD, flags));
@@ -59,8 +66,12 @@ public sealed interface FieldBuilder
/**
* Sets the field access flags.
*
* @param flags the access flags, as a bit mask
* @return this builder
* @see AccessFlags
* @see AccessFlag.Location#FIELD
* @see ClassBuilder#withField(String, ClassDesc, int)
*/
default FieldBuilder withFlags(AccessFlag... flags) {
return with(new AccessFlagsImpl(AccessFlag.Location.FIELD, flags));

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -27,9 +27,18 @@ package java.lang.classfile;
import java.lang.classfile.attribute.*;
/**
* A marker interface for elements that can appear when traversing
* a {@link FieldModel} or be presented to a {@link FieldBuilder}.
* Marker interface for a member element of a {@link FieldModel}. Such an
* element can appear when traversing a {@link FieldModel} unless otherwise
* specified, be supplied to a {@link FieldBuilder}, and be processed by a
* {@link FieldTransform}.
* <p>
* {@link AccessFlags} is the only member element of a field that appear exactly
* once during the traversal of a {@link FieldModel}.
*
* @see ClassFileElement##membership Membership Elements
* @see ClassElement
* @see MethodElement
* @see CodeElement
* @sealedGraph
* @since 24
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -27,24 +27,43 @@ package java.lang.classfile;
import java.lang.classfile.constantpool.Utf8Entry;
import java.lang.constant.ClassDesc;
import java.lang.reflect.AccessFlag;
import java.util.Optional;
import java.util.function.Consumer;
import jdk.internal.classfile.impl.BufferedFieldBuilder;
import jdk.internal.classfile.impl.FieldImpl;
import jdk.internal.classfile.impl.Util;
/**
* Models a field. The contents of the field can be traversed via
* a streaming view, or via random access (e.g.,
* {@link #flags()}), or by freely mixing the two.
* Models a field. A field can be viewed as a {@linkplain CompoundElement
* composition} of {@link FieldElement}s, or by random access via accessor
* methods if only specific parts of the field is needed.
* <p>
* Fields can be obtained from {@link ClassModel#fields()}, or in the traversal
* of member elements of a class.
* <p>
* {@link ClassBuilder#withField(String, ClassDesc, Consumer)} is the main way
* to construct fields. {@link ClassBuilder#transformField} allows creating a
* new field by selectively processing the original field elements and directing
* the results to a field builder.
* <p>
* All field attributes are accessible as member elements.
*
* @see ClassModel#fields()
* @see FieldTransform
* @jvms 4.5 Fields
* @since 24
*/
public sealed interface FieldModel
extends CompoundElement<FieldElement>, AttributedElement, ClassElement
permits BufferedFieldBuilder.Model, FieldImpl {
/** {@return the access flags} */
/**
* {@return the access flags}
*
* @see AccessFlag.Location#FIELD
*/
AccessFlags flags();
/** {@return the class model this field is a member of, if known} */
@@ -53,10 +72,10 @@ public sealed interface FieldModel
/** {@return the name of this field} */
Utf8Entry fieldName();
/** {@return the field descriptor of this field} */
/** {@return the field descriptor string of this field} */
Utf8Entry fieldType();
/** {@return the field descriptor of this field, as a symbolic descriptor} */
/** {@return the field type, as a symbolic descriptor} */
default ClassDesc fieldTypeSymbol() {
return Util.fieldTypeSymbol(fieldType());
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -34,9 +34,17 @@ import static java.util.Objects.requireNonNull;
/**
* A transformation on streams of {@link FieldElement}.
* <p>
* Refer to {@link ClassFileTransform} for general guidance and caution around
* the use of transforms for structures in the {@code class} file format.
* <p>
* A field transform can be lifted to a class transform via {@link
* ClassTransform#transformingFields(FieldTransform)}, transforming only
* the {@link FieldModel} among the class members and passing all other elements
* to the builders.
*
* @see ClassFileTransform
*
* @see FieldModel
* @see ClassBuilder#transformField
* @since 24
*/
@FunctionalInterface
@@ -44,7 +52,7 @@ public non-sealed interface FieldTransform
extends ClassFileTransform<FieldTransform, FieldElement, FieldBuilder> {
/**
* A field transform that sends all elements to the builder.
* A field transform that passes all elements to the builder.
*/
FieldTransform ACCEPT_ALL = new FieldTransform() {
@Override
@@ -54,7 +62,7 @@ public non-sealed interface FieldTransform
};
/**
* Create a stateful field transform from a {@link Supplier}. The supplier
* Creates a stateful field transform from a {@link Supplier}. The supplier
* will be invoked for each transformation.
*
* @param supplier a {@link Supplier} that produces a fresh transform object
@@ -66,7 +74,7 @@ public non-sealed interface FieldTransform
}
/**
* Create a field transform that passes each element through to the builder,
* Creates a field transform that passes each element through to the builder,
* and calls the specified function when transformation is complete.
*
* @param finisher the function to call when transformation is complete
@@ -88,7 +96,7 @@ public non-sealed interface FieldTransform
}
/**
* Create a field transform that passes each element through to the builder,
* Creates a field transform that passes each element through to the builder,
* except for those that the supplied {@link Predicate} is true for.
*
* @param filter the predicate that determines which elements to drop

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -25,13 +25,23 @@
package java.lang.classfile;
import java.lang.classfile.attribute.CodeAttribute;
import java.lang.classfile.instruction.*;
import jdk.internal.classfile.impl.AbstractInstruction;
/**
* Models an executable instruction in a method body.
* Models an executable instruction in the {@code code} array of the {@link
* CodeAttribute Code} attribute of a method. The order of instructions in
* a {@link CodeModel} is significant.
* <p>
* The {@link #opcode() opcode} identifies the operation of an instruction.
* Each {@linkplain Opcode#kind() kind} of opcode has its own modeling interface
* for instructions.
*
* @see Opcode
* @jvms 6.5 Instructions
* @sealedGraph
* @since 24
*/
public sealed interface Instruction extends CodeElement
@@ -46,12 +56,14 @@ public sealed interface Instruction extends CodeElement
ThrowInstruction, TypeCheckInstruction, AbstractInstruction {
/**
* {@return the opcode of this instruction}
* {@return the operation of this instruction}
*/
Opcode opcode();
/**
* {@return the size in bytes of this instruction}
* This value is equal to {@link Opcode#sizeIfFixed()
* opcode().sizeIfFixed()} if it is not {@code -1}.
*/
int sizeInBytes();
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -33,16 +33,22 @@ import jdk.internal.classfile.impl.InterfacesImpl;
import jdk.internal.classfile.impl.Util;
/**
* Models the interfaces of a class. Delivered as a {@link
* java.lang.classfile.ClassElement} when traversing a {@link ClassModel}.
* Models the interfaces (JVMS {@jvms 4.1}) of a class. An {@code Interfaces}
* appears at most once in a {@link ClassModel}: if it does not appear, the
* class has no interfaces, which is equivalent to an {@code Interfaces} whose
* {@link #interfaces()} returns an empty list. A {@link ClassBuilder} sets
* the interfaces to an empty list if the interfaces is not supplied.
*
* @see ClassModel#interfaces()
* @see ClassBuilder#withInterfaces
* @jvms 4.1 The {@code ClassFile} Structure
* @since 24
*/
public sealed interface Interfaces
extends ClassElement
permits InterfacesImpl {
/** {@return the interfaces of this class} */
/** {@return the interfaces of this class, may be empty} */
List<ClassEntry> interfaces();
/**
@@ -64,6 +70,7 @@ public sealed interface Interfaces
/**
* {@return an {@linkplain Interfaces} element}
* @param interfaces the interfaces
* @throws IllegalArgumentException if any of {@code interfaces} is primitive
*/
static Interfaces ofSymbols(List<ClassDesc> interfaces) {
return of(Util.entryList(interfaces));
@@ -72,6 +79,7 @@ public sealed interface Interfaces
/**
* {@return an {@linkplain Interfaces} element}
* @param interfaces the interfaces
* @throws IllegalArgumentException if any of {@code interfaces} is primitive
*/
static Interfaces ofSymbols(ClassDesc... interfaces) {
return ofSymbols(Arrays.asList(interfaces));

View File

@@ -24,21 +24,60 @@
*/
package java.lang.classfile;
import java.lang.classfile.attribute.CodeAttribute;
import java.lang.classfile.instruction.LabelTarget;
import java.util.ListIterator;
import jdk.internal.classfile.impl.LabelImpl;
/**
* A marker for a position within the instructions of a method body. The
* association between a label's identity and the position it represents is
* managed by the entity managing the method body (a {@link CodeModel} or {@link
* CodeBuilder}), not the label itself; this allows the same label to have a
* meaning both in an existing method (as managed by a {@linkplain CodeModel})
* and in the transformation of that method (as managed by a {@linkplain
* CodeBuilder}), while corresponding to different positions in each. When
* traversing the elements of a {@linkplain CodeModel}, {@linkplain Label}
* markers will be delivered at the position to which they correspond. A label
* can be bound to the current position within a {@linkplain CodeBuilder} via
* {@link CodeBuilder#labelBinding(Label)} or {@link CodeBuilder#with(ClassFileElement)}.
* position is a cursor position in the list of instructions, similar to that
* of a {@link ListIterator}.
*
* <h2 id="reading">Reading Labels</h2>
* Labels read from {@code class} files represent positions in the {@code code}
* array of a {@link CodeAttribute Code} attribute. It is associated with a
* <dfn>{@index bci}</dfn> (bytecode index), also known as <dfn>{@index pc}</dfn>
* (program counter), the index into the {@code code} array; the actual cursor
* position is immediately before the given index, so a label at the beginning
* of the instructions has bci {@code 0}, and a label at the end of the
* instructions has bci {@link CodeAttribute#codeLength codeLength() + 1}. The
* bci can be inspected through {@link CodeAttribute#labelToBci
* CodeAttribute::labelToBci}.
* <p>
* In generic {@link CodeModel}s, a label may not have a bci value; the position
* of a label can be found by searching for the corresponding {@link LabelTarget}
* within that model.
*
* <h2 id="writing">Writing Labels</h2>
* Many models in {@link java.lang.classfile} refer to labels. To write a
* label, a label must be obtained, it must be bound to a {@link CodeBuilder}.
* <p>
* To obtain a label:
* <ul>
* <li>Use a label read from other models.
* <li>Use pre-defined labels from a {@link CodeBuilder}, such as {@link
* CodeBuilder#startLabel() CodeBuilder::startLabel}, {@link CodeBuilder#endLabel
* CodeBuilder::endLabel}, or {@link CodeBuilder.BlockCodeBuilder#breakLabel
* BlockCodeBuilder::breakLabel}. They are already bound.
* <li>Create labels with {@link CodeBuilder#newLabel CodeBuilder::newLabel} or
* {@link CodeBuilder#newBoundLabel CodeBuilder::newBoundLabel}.
* </ul>
* <p>
* A label must be bound exactly once in the {@code CodeBuilder} where it is
* used; otherwise, writing fails. To bind an unbound label:
* <ul>
* <li>Send a read {@link LabelTarget} to a {@code CodeBuilder}.
* <li>Use {@link CodeBuilder#labelBinding CodeBuilder::labelBinding}.
* </ul>
* Note that a label read from another model is not automatically bound in a
* {@code CodeBuilder}; they are separate entities and the label is bound to
* different positions in them.
*
* @see CodeAttribute#labelToBci CodeAttribute::labelToBci
* @see CodeBuilder#newLabel CodeBuilder::newLabel
* @see CodeBuilder#labelBinding CodeBuilder::labelBinding
* @since 24
*/
public sealed interface Label

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -25,7 +25,7 @@
package java.lang.classfile;
import java.lang.classfile.constantpool.Utf8Entry;
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.AccessFlag;
import java.util.function.Consumer;
@@ -34,14 +34,18 @@ import jdk.internal.classfile.impl.ChainedMethodBuilder;
import jdk.internal.classfile.impl.TerminalMethodBuilder;
/**
* A builder for methods. Builders are not created directly; they are passed
* to handlers by methods such as {@link ClassBuilder#withMethod(Utf8Entry, Utf8Entry, int, Consumer)}
* or to method transforms. The elements of a method can be specified
* abstractly (by passing a {@link MethodElement} to {@link #with(ClassFileElement)}
* or concretely by calling the various {@code withXxx} methods.
* A builder for methods. The main way to obtain a method builder is via {@link
* ClassBuilder#withMethod(String, MethodTypeDesc, int, Consumer)}. {@link
* ClassBuilder#withMethodBody(String, MethodTypeDesc, int, Consumer)} is
* useful if no attribute on the method except {@link CodeModel Code} needs to
* be configured, skipping the method handler.
* <p>
* Refer to {@link ClassFileBuilder} for general guidance and caution around
* the use of builders for structures in the {@code class} file format.
*
* @see MethodModel
* @see MethodTransform
*
* @jvms 4.6 Methods
* @since 24
*/
public sealed interface MethodBuilder
@@ -49,18 +53,30 @@ public sealed interface MethodBuilder
permits ChainedMethodBuilder, TerminalMethodBuilder {
/**
* Sets the method access flags.
* Sets the method access flags. The {@link AccessFlag#STATIC} flag cannot
* be modified after the builder is created.
*
* @param flags the access flags, as a bit mask
* @return this builder
* @throws IllegalArgumentException if the {@link ClassFile#ACC_STATIC
* ACC_STATIC} flag is modified
* @see AccessFlags
* @see AccessFlag.Location#METHOD
*/
default MethodBuilder withFlags(int flags) {
return with(new AccessFlagsImpl(AccessFlag.Location.METHOD, flags));
}
/**
* Sets the method access flags.
* Sets the method access flags. The {@link AccessFlag#STATIC} flag cannot
* be modified after the builder is created.
*
* @param flags the access flags, as a bit mask
* @return this builder
* @throws IllegalArgumentException if the {@link ClassFile#ACC_STATIC
* ACC_STATIC} flag is modified
* @see AccessFlags
* @see AccessFlag.Location#METHOD
*/
default MethodBuilder withFlags(AccessFlag... flags) {
return with(new AccessFlagsImpl(AccessFlag.Location.METHOD, flags));
@@ -68,24 +84,26 @@ public sealed interface MethodBuilder
/**
* Build the method body for this method.
*
* @param code a handler receiving a {@link CodeBuilder}
* @return this builder
* @see CodeModel
*/
MethodBuilder withCode(Consumer<? super CodeBuilder> code);
/**
* Build the method body for this method by transforming the body of another
* method.
*
* @implNote
* <p>This method behaves as if:
* <p>
* This method behaves as if:
* {@snippet lang=java :
* withCode(b -> b.transformCode(code, transform));
* withCode(cob -> cob.transform(code, transform));
* }
*
* @param code the method body to be transformed
* @param transform the transform to apply to the method body
* @return this builder
* @see CodeTransform
*/
MethodBuilder transformCode(CodeModel code, CodeTransform transform);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -27,9 +27,18 @@ package java.lang.classfile;
import java.lang.classfile.attribute.*;
/**
* A marker interface for elements that can appear when traversing
* a {@link MethodModel} or be presented to a {@link MethodBuilder}.
* Marker interface for a member element of a {@link MethodModel}. Such an
* element can appear when traversing a {@link MethodModel} unless otherwise
* specified, be supplied to a {@link MethodBuilder}, and be processed by a
* {@link MethodTransform}.
* <p>
* {@link AccessFlags} is the only member element of a method that appear
* exactly once during the traversal of a {@link MethodModel}.
*
* @see ClassFileElement##membership Membership Elements
* @see ClassElement
* @see FieldElement
* @see CodeElement
* @sealedGraph
* @since 24
*/

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 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
@@ -27,24 +27,43 @@ package java.lang.classfile;
import java.lang.classfile.constantpool.Utf8Entry;
import java.lang.constant.MethodTypeDesc;
import java.lang.reflect.AccessFlag;
import java.util.Optional;
import java.util.function.Consumer;
import jdk.internal.classfile.impl.BufferedMethodBuilder;
import jdk.internal.classfile.impl.MethodImpl;
import jdk.internal.classfile.impl.Util;
/**
* Models a method. The contents of the method can be traversed via
* a streaming view, or via random access (e.g.,
* {@link #flags()}), or by freely mixing the two.
* Models a method. A method can be viewed as a {@linkplain CompoundElement
* composition} of {@link MethodElement}s, or by random access via accessor
* methods if only specific parts of the method is needed.
* <p>
* Methods can be obtained from {@link ClassModel#methods()}, or in the
* traversal of member elements of a class.
* <p>
* {@link ClassBuilder#withMethod(String, MethodTypeDesc, int, Consumer)} is the
* main way to construct methods. {@link ClassBuilder#transformMethod} allows
* creating a new method by selectively processing the original method elements
* and directing the results to a method builder.
* <p>
* All method attributes are accessible as member elements.
*
* @see ClassModel#methods()
* @see MethodTransform
* @jvms 4.6 Methods
* @since 24
*/
public sealed interface MethodModel
extends CompoundElement<MethodElement>, AttributedElement, ClassElement
permits BufferedMethodBuilder.Model, MethodImpl {
/** {@return the access flags} */
/**
* {@return the access flags}
*
* @see AccessFlag.Location#METHOD
*/
AccessFlags flags();
/** {@return the class model this method is a member of, if known} */
@@ -53,10 +72,10 @@ public sealed interface MethodModel
/** {@return the name of this method} */
Utf8Entry methodName();
/** {@return the method descriptor of this method} */
/** {@return the method descriptor string of this method} */
Utf8Entry methodType();
/** {@return the method descriptor of this method, as a symbolic descriptor} */
/** {@return the method type, as a symbolic descriptor} */
default MethodTypeDesc methodTypeSymbol() {
return Util.methodTypeSymbol(methodType());
}

Some files were not shown because too many files have changed in this diff Show More