mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-07 09:59:37 +01:00
Compare commits
88 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6705a9255d | ||
|
|
681c6d4339 | ||
|
|
f0837b2183 | ||
|
|
b1659e345a | ||
|
|
47c15b5ff8 | ||
|
|
5f5ed961db | ||
|
|
df57c97d29 | ||
|
|
2a1a416c37 | ||
|
|
89c46f11f8 | ||
|
|
b1b55f712c | ||
|
|
15f90f0c7b | ||
|
|
926455d6c5 | ||
|
|
ec00b6b7ac | ||
|
|
2d4731917d | ||
|
|
612ae737c0 | ||
|
|
a315b9326b | ||
|
|
ab43ba0ef8 | ||
|
|
564e0a2076 | ||
|
|
53aa9f2596 | ||
|
|
99e21c6aaf | ||
|
|
4ce95c95ef | ||
|
|
93ea8e708d | ||
|
|
a9fae67913 | ||
|
|
aaf3415de8 | ||
|
|
535922059c | ||
|
|
bc19494216 | ||
|
|
febcfd69ff | ||
|
|
1495f7addb | ||
|
|
c141aa1e08 | ||
|
|
467f407037 | ||
|
|
f7858e2422 | ||
|
|
6965840e0d | ||
|
|
1399f253b0 | ||
|
|
f45a23cabd | ||
|
|
f42e2c10c6 | ||
|
|
57c46ac2fe | ||
|
|
24053d9b6a | ||
|
|
e76cc44502 | ||
|
|
4a623a2b6d | ||
|
|
ecdc322029 | ||
|
|
da74fbd920 | ||
|
|
f0a89c5d8e | ||
|
|
c61fbfd6ea | ||
|
|
92a4e23467 | ||
|
|
ba36d309c3 | ||
|
|
41630c5c32 | ||
|
|
864d0fde23 | ||
|
|
ff9b8e4607 | ||
|
|
7d4fa7818b | ||
|
|
c033806b8c | ||
|
|
bf45128055 | ||
|
|
29c6bf23fb | ||
|
|
c3b52089f6 | ||
|
|
860b30ddf9 | ||
|
|
256856a5a1 | ||
|
|
cc7c293bce | ||
|
|
33971ecb6e | ||
|
|
4254e99ce2 | ||
|
|
05c3769986 | ||
|
|
ab78b04cf6 | ||
|
|
bed040191b | ||
|
|
5d138cbba0 | ||
|
|
63aa68a7c6 | ||
|
|
f0ada9f34e | ||
|
|
303736b038 | ||
|
|
2c336299aa | ||
|
|
4aec2d4ef9 | ||
|
|
b8249c5d90 | ||
|
|
0225372e0b | ||
|
|
2cc14faa21 | ||
|
|
f703b6e7b1 | ||
|
|
297b21fb60 | ||
|
|
67b8251679 | ||
|
|
6e8aad1ad4 | ||
|
|
4d6eccd9fc | ||
|
|
6bc14d6b77 | ||
|
|
897a8abecc | ||
|
|
3b53ed7fb0 | ||
|
|
6fdfa72996 | ||
|
|
950c8adfd7 | ||
|
|
03bdee0f75 | ||
|
|
4ecb28ccdc | ||
|
|
ba02e0bd1b | ||
|
|
253030a6d4 | ||
|
|
a81325433d | ||
|
|
203422a8ed | ||
|
|
8e9ba788ae | ||
|
|
3aa07dbf14 |
@@ -29,6 +29,7 @@ include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
|
||||
include CopyFiles.gmk
|
||||
include DebugInfoUtils.gmk
|
||||
include Execute.gmk
|
||||
include Modules.gmk
|
||||
include Utils.gmk
|
||||
|
||||
@@ -29,6 +29,7 @@ include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
|
||||
include CopyFiles.gmk
|
||||
include DebugInfoUtils.gmk
|
||||
include Modules.gmk
|
||||
include modules/LauncherCommon.gmk
|
||||
|
||||
|
||||
58
make/common/DebugInfoUtils.gmk
Normal file
58
make/common/DebugInfoUtils.gmk
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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=
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
|
||||
@@ -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 :
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user