mirror of
https://github.com/openjdk/jdk.git
synced 2026-04-11 07:28:36 +00:00
Merge branch 'master' into opt-simploop-8346177
This commit is contained in:
commit
22a3526dad
5
.github/pull_request_template.md
vendored
Normal file
5
.github/pull_request_template.md
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
|
||||
---------
|
||||
- [ ] I confirm that I make this contribution in accordance with the [OpenJDK Interim AI Policy](https://openjdk.org/legal/ai).
|
||||
@ -44,6 +44,9 @@ ifeq ($(HSDIS_BACKEND), capstone)
|
||||
else ifeq ($(call isTargetCpuArch, aarch64), true)
|
||||
CAPSTONE_ARCH := CS_ARCH_$(CAPSTONE_ARCH_AARCH64_NAME)
|
||||
CAPSTONE_MODE := CS_MODE_ARM
|
||||
else ifeq ($(call isTargetCpuArch, arm), true)
|
||||
CAPSTONE_ARCH := CS_ARCH_ARM
|
||||
CAPSTONE_MODE := CS_MODE_ARM
|
||||
else
|
||||
$(error No support for Capstone on this platform)
|
||||
endif
|
||||
|
||||
@ -87,6 +87,7 @@ public class CLDRConverter {
|
||||
static final String EXEMPLAR_CITY_PREFIX = "timezone.excity.";
|
||||
static final String ZONE_NAME_PREFIX = "timezone.displayname.";
|
||||
static final String METAZONE_ID_PREFIX = "metazone.id.";
|
||||
static final String METAZONE_DSTOFFSET_PREFIX = "metazone.dstoffset.";
|
||||
static final String PARENT_LOCALE_PREFIX = "parentLocale.";
|
||||
static final String LIKELY_SCRIPT_PREFIX = "likelyScript.";
|
||||
static final String META_EMPTY_ZONE_NAME = "EMPTY_ZONE";
|
||||
@ -139,6 +140,11 @@ public class CLDRConverter {
|
||||
private static final Map<String, String> tzdbSubstLetters = HashMap.newHashMap(512);
|
||||
private static final Map<String, String> tzdbLinks = HashMap.newHashMap(512);
|
||||
|
||||
// Map of explicit dst offsets for metazones
|
||||
// key: time zone ID
|
||||
// value: explicit dstOffset for the corresponding metazone name
|
||||
static final Map<String, String> explicitDstOffsets = HashMap.newHashMap(32);
|
||||
|
||||
static enum DraftType {
|
||||
UNCONFIRMED,
|
||||
PROVISIONAL,
|
||||
@ -867,6 +873,12 @@ public class CLDRConverter {
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
names.putAll(exCities);
|
||||
|
||||
// Explicit metazone offsets
|
||||
if (id.equals("root")) {
|
||||
explicitDstOffsets.forEach((k, v) ->
|
||||
names.put(METAZONE_DSTOFFSET_PREFIX + k, v));
|
||||
}
|
||||
|
||||
// If there's no UTC entry at this point, add an empty one
|
||||
if (!names.isEmpty() && !names.containsKey("UTC")) {
|
||||
names.putIfAbsent(METAZONE_ID_PREFIX + META_EMPTY_ZONE_NAME, EMPTY_ZONE);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -84,7 +84,15 @@ class MetaZonesParseHandler extends AbstractLDMLHandler<String> {
|
||||
|
||||
if (fromLDT.isBefore(now) && toLDT.isAfter(now)) {
|
||||
metazone = attributes.getValue("mzone");
|
||||
|
||||
// Explicit metazone DST offsets. Only the "dst" offset is needed,
|
||||
// as "std" is used by default when it doesn't match.
|
||||
String dstOffset = attributes.getValue("dstOffset");
|
||||
if (dstOffset != null) {
|
||||
CLDRConverter.explicitDstOffsets.put(tzid, dstOffset);
|
||||
}
|
||||
}
|
||||
|
||||
pushIgnoredContainer(qName);
|
||||
break;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -198,7 +198,8 @@ class ResourceBundleGenerator implements BundleGenerator {
|
||||
} else if (value instanceof String) {
|
||||
String valStr = (String)value;
|
||||
if (type == BundleType.TIMEZONE &&
|
||||
!key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) ||
|
||||
!(key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) ||
|
||||
key.startsWith(CLDRConverter.METAZONE_DSTOFFSET_PREFIX)) ||
|
||||
valStr.startsWith(META_VALUE_PREFIX)) {
|
||||
out.printf(" { \"%s\", %s },\n", key, CLDRConverter.saveConvert(valStr, useJava));
|
||||
} else {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
@ -55,6 +55,12 @@ else
|
||||
LIBSAPROC_LINK_TYPE := C
|
||||
endif
|
||||
|
||||
# DWARF related sources would be included on supported platforms only.
|
||||
LIBSAPROC_EXCLUDE_FILES :=
|
||||
ifneq ($(call And, $(call isTargetOs, linux) $(call isTargetCpu, x86_64 aarch64)), true)
|
||||
LIBSAPROC_EXCLUDE_FILES := DwarfParser.cpp dwarf.cpp
|
||||
endif
|
||||
|
||||
$(eval $(call SetupJdkLibrary, BUILD_LIBSAPROC, \
|
||||
NAME := saproc, \
|
||||
LINK_TYPE := $(LIBSAPROC_LINK_TYPE), \
|
||||
@ -70,6 +76,7 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBSAPROC, \
|
||||
CFLAGS := $(LIBSAPROC_CFLAGS), \
|
||||
CXXFLAGS := $(LIBSAPROC_CFLAGS) $(LIBSAPROC_CXXFLAGS), \
|
||||
EXTRA_SRC := $(LIBSAPROC_EXTRA_SRC), \
|
||||
EXCLUDE_FILES := $(LIBSAPROC_EXCLUDE_FILES), \
|
||||
JDK_LIBS := java.base:libjava, \
|
||||
LIBS_linux := $(LIBDL), \
|
||||
LIBS_macosx := \
|
||||
|
||||
@ -1098,6 +1098,7 @@ void VM_Version::get_processor_features() {
|
||||
if (supports_apx_f() && os_supports_apx_egprs() && supports_avx512vl()) {
|
||||
if (FLAG_IS_DEFAULT(UseAPX)) {
|
||||
UseAPX = false; // by default UseAPX is false
|
||||
_features.clear_feature(CPU_APX_F);
|
||||
} else if (!UseAPX) {
|
||||
_features.clear_feature(CPU_APX_F);
|
||||
}
|
||||
@ -1206,16 +1207,7 @@ void VM_Version::get_processor_features() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!UseAES) {
|
||||
if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
|
||||
warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled.");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAESIntrinsics, false);
|
||||
if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
|
||||
warning("AES_CTR intrinsics require UseAES flag to be enabled. AES_CTR intrinsics will be disabled.");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
|
||||
} else if (!cpu_supports_aes()) {
|
||||
if (!cpu_supports_aes()) {
|
||||
if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
|
||||
warning("AES intrinsics are not available on this CPU");
|
||||
}
|
||||
@ -1224,6 +1216,15 @@ void VM_Version::get_processor_features() {
|
||||
warning("AES-CTR intrinsics are not available on this CPU");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
|
||||
} else if (!UseAES) {
|
||||
if (UseAESIntrinsics && !FLAG_IS_DEFAULT(UseAESIntrinsics)) {
|
||||
warning("AES intrinsics require UseAES flag to be enabled. Intrinsics will be disabled.");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAESIntrinsics, false);
|
||||
if (UseAESCTRIntrinsics && !FLAG_IS_DEFAULT(UseAESCTRIntrinsics)) {
|
||||
warning("AES_CTR intrinsics require UseAES flag to be enabled. AES_CTR intrinsics will be disabled.");
|
||||
}
|
||||
FLAG_SET_DEFAULT(UseAESCTRIntrinsics, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -2163,8 +2163,6 @@ void os::print_os_info(outputStream* st) {
|
||||
|
||||
os::Posix::print_rlimit_info(st);
|
||||
|
||||
os::print_open_file_descriptors(st);
|
||||
|
||||
os::Posix::print_load_average(st);
|
||||
st->cr();
|
||||
|
||||
|
||||
@ -1905,9 +1905,6 @@ void AOTCodeAddressTable::init_extrs() {
|
||||
ADD_EXTERNAL_ADDRESS(SharedRuntime::handle_wrong_method_ic_miss);
|
||||
#if defined(AARCH64) && !defined(ZERO)
|
||||
ADD_EXTERNAL_ADDRESS(JavaThread::aarch64_get_thread_helper);
|
||||
#endif
|
||||
|
||||
#if defined(AARCH64)
|
||||
ADD_EXTERNAL_ADDRESS(BarrierSetAssembler::patching_epoch_addr());
|
||||
#endif
|
||||
|
||||
|
||||
@ -45,9 +45,10 @@ class OopMapSet;
|
||||
enum class CodeBlobType {
|
||||
MethodNonProfiled = 0, // Execution level 1 and 4 (non-profiled) nmethods (including native nmethods)
|
||||
MethodProfiled = 1, // Execution level 2 and 3 (profiled) nmethods
|
||||
NonNMethod = 2, // Non-nmethods like Buffers, Adapters and Runtime Stubs
|
||||
All = 3, // All types (No code cache segmentation)
|
||||
NumTypes = 4 // Number of CodeBlobTypes
|
||||
MethodHot = 2, // Nmethods predicted to be always hot
|
||||
NonNMethod = 3, // Non-nmethods like Buffers, Adapters and Runtime Stubs
|
||||
All = 4, // All types (No code cache segmentation)
|
||||
NumTypes = 5 // Number of CodeBlobTypes
|
||||
};
|
||||
|
||||
// CodeBlob - superclass for all entries in the CodeCache.
|
||||
|
||||
@ -201,6 +201,7 @@ void CodeCache::initialize_heaps() {
|
||||
CodeHeapInfo non_nmethod = {NonNMethodCodeHeapSize, FLAG_IS_CMDLINE(NonNMethodCodeHeapSize), true};
|
||||
CodeHeapInfo profiled = {ProfiledCodeHeapSize, FLAG_IS_CMDLINE(ProfiledCodeHeapSize), true};
|
||||
CodeHeapInfo non_profiled = {NonProfiledCodeHeapSize, FLAG_IS_CMDLINE(NonProfiledCodeHeapSize), true};
|
||||
CodeHeapInfo hot = {HotCodeHeapSize, FLAG_IS_CMDLINE(HotCodeHeapSize), true};
|
||||
|
||||
const bool cache_size_set = FLAG_IS_CMDLINE(ReservedCodeCacheSize);
|
||||
const size_t ps = page_size(false, 8);
|
||||
@ -219,6 +220,12 @@ void CodeCache::initialize_heaps() {
|
||||
profiled.enabled = false;
|
||||
}
|
||||
|
||||
if (!heap_available(CodeBlobType::MethodHot)) {
|
||||
hot.size = 0;
|
||||
hot.set = true;
|
||||
hot.enabled = false;
|
||||
}
|
||||
|
||||
assert(heap_available(CodeBlobType::MethodNonProfiled), "MethodNonProfiled heap is always available for segmented code heap");
|
||||
|
||||
size_t compiler_buffer_size = 0;
|
||||
@ -238,14 +245,36 @@ void CodeCache::initialize_heaps() {
|
||||
set_size_of_unset_code_heap(&non_profiled, cache_size, non_nmethod.size + profiled.size, min_size);
|
||||
}
|
||||
|
||||
if (!profiled.set && non_profiled.set) {
|
||||
set_size_of_unset_code_heap(&profiled, cache_size, non_nmethod.size + non_profiled.size, min_size);
|
||||
if (!profiled.set && non_profiled.set && hot.set) {
|
||||
set_size_of_unset_code_heap(&profiled, cache_size, non_nmethod.size + non_profiled.size + hot.size, min_size);
|
||||
}
|
||||
|
||||
if (hot.enabled) {
|
||||
if (!hot.set) {
|
||||
assert(hot.size == 0, "must be calculated during heaps initialization");
|
||||
// An application usually has ~20% hot code which is mostly non-profiled code.
|
||||
// We set the hot code heap size to 20% of the non-profiled code heap.
|
||||
hot.size = MAX2(non_profiled.size / 5, min_size);
|
||||
|
||||
if (non_profiled.set) {
|
||||
err_msg msg("Must manually set HotCodeHeapSize when NonProfiledCodeHeapSize is set");
|
||||
vm_exit_during_initialization("Invalid code heap sizes", msg);
|
||||
}
|
||||
|
||||
non_profiled.size -= hot.size;
|
||||
}
|
||||
|
||||
if (hot.size > non_profiled.size) {
|
||||
err_msg msg("Hot (%zuK) exceeds NonProfiled (%zuK).",
|
||||
hot.size / K, non_profiled.size / K);
|
||||
vm_exit_during_initialization("Invalid code heap sizes", msg);
|
||||
}
|
||||
}
|
||||
|
||||
// Compatibility.
|
||||
size_t non_nmethod_min_size = min_cache_size + compiler_buffer_size;
|
||||
if (!non_nmethod.set && profiled.set && non_profiled.set) {
|
||||
set_size_of_unset_code_heap(&non_nmethod, cache_size, profiled.size + non_profiled.size, non_nmethod_min_size);
|
||||
if (!non_nmethod.set && profiled.set && non_profiled.set && hot.set) {
|
||||
set_size_of_unset_code_heap(&non_nmethod, cache_size, profiled.size + non_profiled.size + hot.size, non_nmethod_min_size);
|
||||
}
|
||||
|
||||
// Note: if large page support is enabled, min_size is at least the large
|
||||
@ -253,8 +282,9 @@ void CodeCache::initialize_heaps() {
|
||||
non_nmethod.size = align_up(non_nmethod.size, min_size);
|
||||
profiled.size = align_up(profiled.size, min_size);
|
||||
non_profiled.size = align_up(non_profiled.size, min_size);
|
||||
hot.size = align_up(hot.size, min_size);
|
||||
|
||||
size_t aligned_total = non_nmethod.size + profiled.size + non_profiled.size;
|
||||
size_t aligned_total = non_nmethod.size + profiled.size + non_profiled.size + hot.size;
|
||||
if (!cache_size_set) {
|
||||
// If ReservedCodeCacheSize is explicitly set and exceeds CODE_CACHE_SIZE_LIMIT,
|
||||
// it is rejected by flag validation elsewhere. Here we only handle the case
|
||||
@ -262,15 +292,15 @@ void CodeCache::initialize_heaps() {
|
||||
// sizes (after alignment) exceed the platform limit.
|
||||
if (aligned_total > CODE_CACHE_SIZE_LIMIT) {
|
||||
err_msg message("ReservedCodeCacheSize (%zuK), Max (%zuK)."
|
||||
"Segments: NonNMethod (%zuK), NonProfiled (%zuK), Profiled (%zuK).",
|
||||
"Segments: NonNMethod (%zuK), NonProfiled (%zuK), Profiled (%zuK), Hot (%zuK).",
|
||||
aligned_total/K, CODE_CACHE_SIZE_LIMIT/K,
|
||||
non_nmethod.size/K, non_profiled.size/K, profiled.size/K);
|
||||
non_nmethod.size/K, non_profiled.size/K, profiled.size/K, hot.size/K);
|
||||
vm_exit_during_initialization("Code cache size exceeds platform limit", message);
|
||||
}
|
||||
if (aligned_total != cache_size) {
|
||||
log_info(codecache)("ReservedCodeCache size %zuK changed to total segments size NonNMethod "
|
||||
"%zuK NonProfiled %zuK Profiled %zuK = %zuK",
|
||||
cache_size/K, non_nmethod.size/K, non_profiled.size/K, profiled.size/K, aligned_total/K);
|
||||
"%zuK NonProfiled %zuK Profiled %zuK Hot %zuK = %zuK",
|
||||
cache_size/K, non_nmethod.size/K, non_profiled.size/K, profiled.size/K, hot.size/K, aligned_total/K);
|
||||
// Adjust ReservedCodeCacheSize as necessary because it was not set explicitly
|
||||
cache_size = aligned_total;
|
||||
}
|
||||
@ -295,19 +325,23 @@ void CodeCache::initialize_heaps() {
|
||||
}
|
||||
if (profiled.enabled && !profiled.set && profiled.size > min_size) {
|
||||
profiled.size -= min_size;
|
||||
if (--delta == 0) break;
|
||||
}
|
||||
if (hot.enabled && !hot.set && hot.size > min_size) {
|
||||
hot.size -= min_size;
|
||||
delta--;
|
||||
}
|
||||
if (delta == start_delta) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
aligned_total = non_nmethod.size + profiled.size + non_profiled.size;
|
||||
aligned_total = non_nmethod.size + profiled.size + non_profiled.size + hot.size;
|
||||
}
|
||||
}
|
||||
|
||||
log_debug(codecache)("Initializing code heaps ReservedCodeCache %zuK NonNMethod %zuK"
|
||||
" NonProfiled %zuK Profiled %zuK",
|
||||
cache_size/K, non_nmethod.size/K, non_profiled.size/K, profiled.size/K);
|
||||
" NonProfiled %zuK Profiled %zuK Hot %zuK",
|
||||
cache_size/K, non_nmethod.size/K, non_profiled.size/K, profiled.size/K, hot.size/K);
|
||||
|
||||
// Validation
|
||||
// Check minimal required sizes
|
||||
@ -318,6 +352,9 @@ void CodeCache::initialize_heaps() {
|
||||
if (non_profiled.enabled) { // non_profiled.enabled is always ON for segmented code heap, leave it checked for clarity
|
||||
check_min_size("non-profiled code heap", non_profiled.size, min_size);
|
||||
}
|
||||
if (hot.enabled) {
|
||||
check_min_size("hot code heap", hot.size, min_size);
|
||||
}
|
||||
|
||||
// ReservedCodeCacheSize was set explicitly, so report an error and abort if it doesn't match the segment sizes
|
||||
if (aligned_total != cache_size && cache_size_set) {
|
||||
@ -328,6 +365,9 @@ void CodeCache::initialize_heaps() {
|
||||
if (non_profiled.enabled) {
|
||||
message.append(" + NonProfiledCodeHeapSize (%zuK)", non_profiled.size/K);
|
||||
}
|
||||
if (hot.enabled) {
|
||||
message.append(" + HotCodeHeapSize (%zuK)", hot.size/K);
|
||||
}
|
||||
message.append(" = %zuK", aligned_total/K);
|
||||
message.append((aligned_total > cache_size) ? " is greater than " : " is less than ");
|
||||
message.append("ReservedCodeCacheSize (%zuK).", cache_size/K);
|
||||
@ -348,6 +388,7 @@ void CodeCache::initialize_heaps() {
|
||||
FLAG_SET_ERGO(NonNMethodCodeHeapSize, non_nmethod.size);
|
||||
FLAG_SET_ERGO(ProfiledCodeHeapSize, profiled.size);
|
||||
FLAG_SET_ERGO(NonProfiledCodeHeapSize, non_profiled.size);
|
||||
FLAG_SET_ERGO(HotCodeHeapSize, hot.size);
|
||||
FLAG_SET_ERGO(ReservedCodeCacheSize, cache_size);
|
||||
|
||||
ReservedSpace rs = reserve_heap_memory(cache_size, ps);
|
||||
@ -368,6 +409,13 @@ void CodeCache::initialize_heaps() {
|
||||
// Non-nmethods (stubs, adapters, ...)
|
||||
add_heap(non_method_space, "CodeHeap 'non-nmethods'", CodeBlobType::NonNMethod);
|
||||
|
||||
if (hot.enabled) {
|
||||
ReservedSpace hot_space = rs.partition(offset, hot.size);
|
||||
offset += hot.size;
|
||||
// Nmethods known to be always hot.
|
||||
add_heap(hot_space, "CodeHeap 'hot nmethods'", CodeBlobType::MethodHot);
|
||||
}
|
||||
|
||||
if (non_profiled.enabled) {
|
||||
ReservedSpace non_profiled_space = rs.partition(offset, non_profiled.size);
|
||||
// Tier 1 and tier 4 (non-profiled) methods and native methods
|
||||
@ -406,16 +454,25 @@ bool CodeCache::heap_available(CodeBlobType code_blob_type) {
|
||||
// Interpreter only: we don't need any method code heaps
|
||||
return (code_blob_type == CodeBlobType::NonNMethod);
|
||||
} else if (CompilerConfig::is_c1_profiling()) {
|
||||
// Tiered compilation: use all code heaps
|
||||
// Tiered compilation: use all code heaps including
|
||||
// the hot code heap when it is present.
|
||||
|
||||
if (COMPILER2_PRESENT(!HotCodeHeap &&) (code_blob_type == CodeBlobType::MethodHot)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (code_blob_type < CodeBlobType::All);
|
||||
} else {
|
||||
// No TieredCompilation: we only need the non-nmethod and non-profiled code heap
|
||||
// and the hot code heap if it is requested.
|
||||
return (code_blob_type == CodeBlobType::NonNMethod) ||
|
||||
(code_blob_type == CodeBlobType::MethodNonProfiled);
|
||||
(code_blob_type == CodeBlobType::MethodNonProfiled)
|
||||
COMPILER2_PRESENT(|| ((code_blob_type == CodeBlobType::MethodHot) && HotCodeHeap));
|
||||
}
|
||||
}
|
||||
|
||||
const char* CodeCache::get_code_heap_flag_name(CodeBlobType code_blob_type) {
|
||||
// Returns the name of the VM option to set the size of the corresponding CodeHeap
|
||||
static const char* get_code_heap_flag_name(CodeBlobType code_blob_type) {
|
||||
switch(code_blob_type) {
|
||||
case CodeBlobType::NonNMethod:
|
||||
return "NonNMethodCodeHeapSize";
|
||||
@ -426,6 +483,9 @@ const char* CodeCache::get_code_heap_flag_name(CodeBlobType code_blob_type) {
|
||||
case CodeBlobType::MethodProfiled:
|
||||
return "ProfiledCodeHeapSize";
|
||||
break;
|
||||
case CodeBlobType::MethodHot:
|
||||
return "HotCodeHeapSize";
|
||||
break;
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return nullptr;
|
||||
@ -542,7 +602,7 @@ CodeBlob* CodeCache::allocate(uint size, CodeBlobType code_blob_type, bool handl
|
||||
|
||||
// Get CodeHeap for the given CodeBlobType
|
||||
CodeHeap* heap = get_code_heap(code_blob_type);
|
||||
assert(heap != nullptr, "heap is null");
|
||||
assert(heap != nullptr, "No heap for given code_blob_type (%d), heap is null", (int)code_blob_type);
|
||||
|
||||
while (true) {
|
||||
cb = (CodeBlob*)heap->allocate(size);
|
||||
@ -570,6 +630,9 @@ CodeBlob* CodeCache::allocate(uint size, CodeBlobType code_blob_type, bool handl
|
||||
type = CodeBlobType::MethodNonProfiled;
|
||||
}
|
||||
break;
|
||||
case CodeBlobType::MethodHot:
|
||||
type = CodeBlobType::MethodNonProfiled;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@ -118,10 +118,6 @@ class CodeCache : AllStatic {
|
||||
// Creates a new heap with the given name and size, containing CodeBlobs of the given type
|
||||
static void add_heap(ReservedSpace rs, const char* name, CodeBlobType code_blob_type);
|
||||
static CodeHeap* get_code_heap_containing(void* p); // Returns the CodeHeap containing the given pointer, or nullptr
|
||||
static CodeHeap* get_code_heap(const void* cb); // Returns the CodeHeap for the given CodeBlob
|
||||
static CodeHeap* get_code_heap(CodeBlobType code_blob_type); // Returns the CodeHeap for the given CodeBlobType
|
||||
// Returns the name of the VM option to set the size of the corresponding CodeHeap
|
||||
static const char* get_code_heap_flag_name(CodeBlobType code_blob_type);
|
||||
static ReservedSpace reserve_heap_memory(size_t size, size_t rs_ps); // Reserves one continuous chunk of memory for the CodeHeaps
|
||||
|
||||
// Iteration
|
||||
@ -145,6 +141,8 @@ class CodeCache : AllStatic {
|
||||
static int code_heap_compare(CodeHeap* const &lhs, CodeHeap* const &rhs);
|
||||
|
||||
static void add_heap(CodeHeap* heap);
|
||||
static CodeHeap* get_code_heap(const void* cb); // Returns the CodeHeap for the given CodeBlob
|
||||
static CodeHeap* get_code_heap(CodeBlobType code_blob_type); // Returns the CodeHeap for the given CodeBlobType
|
||||
static const GrowableArray<CodeHeap*>* heaps() { return _heaps; }
|
||||
static const GrowableArray<CodeHeap*>* nmethod_heaps() { return _nmethod_heaps; }
|
||||
|
||||
@ -264,7 +262,7 @@ class CodeCache : AllStatic {
|
||||
}
|
||||
|
||||
static bool code_blob_type_accepts_nmethod(CodeBlobType type) {
|
||||
return type == CodeBlobType::All || type <= CodeBlobType::MethodProfiled;
|
||||
return type == CodeBlobType::All || type <= CodeBlobType::MethodHot;
|
||||
}
|
||||
|
||||
static bool code_blob_type_accepts_allocable(CodeBlobType type) {
|
||||
|
||||
@ -66,6 +66,9 @@
|
||||
#include "runtime/flags/flagSetting.hpp"
|
||||
#include "runtime/frame.inline.hpp"
|
||||
#include "runtime/handles.inline.hpp"
|
||||
#ifdef COMPILER2
|
||||
#include "runtime/hotCodeCollector.hpp"
|
||||
#endif // COMPILER2
|
||||
#include "runtime/icache.hpp"
|
||||
#include "runtime/jniHandles.inline.hpp"
|
||||
#include "runtime/orderAccess.hpp"
|
||||
@ -1258,6 +1261,11 @@ void nmethod::post_init() {
|
||||
ICache::invalidate_range(code_begin(), code_size());
|
||||
|
||||
Universe::heap()->register_nmethod(this);
|
||||
|
||||
#ifdef COMPILER2
|
||||
HotCodeCollector::register_nmethod(this);
|
||||
#endif // COMPILER2
|
||||
|
||||
DEBUG_ONLY(Universe::heap()->verify_nmethod(this));
|
||||
|
||||
CodeCache::commit(this);
|
||||
@ -2476,6 +2484,11 @@ void nmethod::purge(bool unregister_nmethod) {
|
||||
if (unregister_nmethod) {
|
||||
Universe::heap()->unregister_nmethod(this);
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
HotCodeCollector::unregister_nmethod(this);
|
||||
#endif // COMPILER2
|
||||
|
||||
CodeCache::unregister_old_nmethod(this);
|
||||
|
||||
JVMCI_ONLY( _metadata_size = 0; )
|
||||
|
||||
@ -286,8 +286,38 @@ void CompilerConfig::set_compilation_policy_flags() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
if (HotCodeHeap) {
|
||||
if (FLAG_IS_DEFAULT(SegmentedCodeCache)) {
|
||||
FLAG_SET_ERGO(SegmentedCodeCache, true);
|
||||
} else if (!SegmentedCodeCache) {
|
||||
vm_exit_during_initialization("HotCodeHeap requires SegmentedCodeCache enabled");
|
||||
}
|
||||
|
||||
if (FLAG_IS_DEFAULT(NMethodRelocation)) {
|
||||
FLAG_SET_ERGO(NMethodRelocation, true);
|
||||
} else if (!NMethodRelocation) {
|
||||
vm_exit_during_initialization("HotCodeHeap requires NMethodRelocation enabled");
|
||||
}
|
||||
|
||||
if (!is_c2_enabled()) {
|
||||
vm_exit_during_initialization("HotCodeHeap requires C2 enabled");
|
||||
}
|
||||
|
||||
if (HotCodeMinSamplingMs > HotCodeMaxSamplingMs) {
|
||||
vm_exit_during_initialization("HotCodeMinSamplingMs cannot be larger than HotCodeMaxSamplingMs");
|
||||
}
|
||||
} else if (HotCodeHeapSize > 0) {
|
||||
vm_exit_during_initialization("HotCodeHeapSize requires HotCodeHeap enabled");
|
||||
}
|
||||
#else
|
||||
if (HotCodeHeapSize > 0) {
|
||||
vm_exit_during_initialization("HotCodeHeapSize requires C2 present");
|
||||
}
|
||||
#endif // COMPILER2
|
||||
|
||||
if (CompileThresholdScaling < 0) {
|
||||
vm_exit_during_initialization("Negative value specified for CompileThresholdScaling", nullptr);
|
||||
vm_exit_during_initialization("Negative value specified for CompileThresholdScaling");
|
||||
}
|
||||
|
||||
if (CompilationModeFlag::disable_intermediate()) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -326,11 +326,14 @@ bool G1ConcurrentRefineSweepState::complete_work(bool concurrent, bool print_log
|
||||
if (print_log) {
|
||||
G1ConcurrentRefineStats* s = &_stats;
|
||||
|
||||
log_debug(gc, refine)("Refinement took %.2fms (pre-sweep %.2fms card refine %.2f) "
|
||||
State state_bounded_by_sweeprt = (_state == State::SweepRT || _state == State::CompleteRefineWork)
|
||||
? State::SweepRT : _state;
|
||||
|
||||
log_debug(gc, refine)("Refinement took %.2fms (pre-sweep %.2fms card refine %.2fms) "
|
||||
"(scanned %zu clean %zu (%.2f%%) not_clean %zu (%.2f%%) not_parsable %zu "
|
||||
"refers_to_cset %zu (%.2f%%) still_refers_to_cset %zu (%.2f%%) no_cross_region %zu pending %zu)",
|
||||
get_duration(State::Idle, _state).seconds() * 1000.0,
|
||||
get_duration(State::Idle, State::SweepRT).seconds() * 1000.0,
|
||||
get_duration(State::Idle, state_bounded_by_sweeprt).seconds() * 1000.0,
|
||||
TimeHelper::counter_to_millis(s->refine_duration()),
|
||||
s->cards_scanned(),
|
||||
s->cards_clean(),
|
||||
|
||||
@ -962,12 +962,12 @@ void G1Policy::record_young_collection_end(bool concurrent_operation_is_full_mar
|
||||
|
||||
_free_regions_at_end_of_collection = _g1h->num_free_regions();
|
||||
|
||||
_old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * G1HeapRegion::GrainBytes);
|
||||
// Do not update dynamic IHOP due to G1 periodic collection as it is highly likely
|
||||
// that in this case we are not running in a "normal" operating mode.
|
||||
if (_g1h->gc_cause() != GCCause::_g1_periodic_collection) {
|
||||
update_young_length_bounds();
|
||||
|
||||
_old_gen_alloc_tracker.reset_after_gc(_g1h->humongous_regions_count() * G1HeapRegion::GrainBytes);
|
||||
if (update_ihop_prediction(app_time_ms / 1000.0, is_young_only_pause)) {
|
||||
_ihop_control->report_statistics(_g1h->gc_tracer_stw(), _g1h->non_young_occupancy_after_allocation(allocation_word_size));
|
||||
}
|
||||
|
||||
@ -96,6 +96,7 @@ class outputStream;
|
||||
LOG_TAG(heap) \
|
||||
LOG_TAG(heapdump) \
|
||||
NOT_PRODUCT(LOG_TAG(heapsampling)) \
|
||||
COMPILER2_PRESENT(LOG_TAG(hotcode)) \
|
||||
LOG_TAG(humongous) \
|
||||
LOG_TAG(ihop) \
|
||||
LOG_TAG(iklass) \
|
||||
|
||||
@ -258,6 +258,19 @@ Node* ArrayCopyNode::try_clone_instance(PhaseGVN *phase, bool can_reshape, int c
|
||||
return mem;
|
||||
}
|
||||
|
||||
// We may have narrowed the type of base because this runs with PhaseIterGVN::_delay_transform true, explicitly
|
||||
// update the type of the AddP so it's consistent with its base and load() picks the right memory slice.
|
||||
Node* ArrayCopyNode::make_and_transform_addp(PhaseGVN* phase, Node* base, Node* offset) {
|
||||
return make_and_transform_addp(phase, base, base, offset);
|
||||
}
|
||||
|
||||
Node* ArrayCopyNode::make_and_transform_addp(PhaseGVN* phase, Node* base, Node* ptr, Node* offset) {
|
||||
assert(phase->is_IterGVN() == nullptr || phase->is_IterGVN()->delay_transform(), "helper method when delay transform is set");
|
||||
Node* addp = phase->transform(AddPNode::make_with_base(base, ptr, offset));
|
||||
phase->set_type(addp, addp->Value(phase));
|
||||
return addp;
|
||||
}
|
||||
|
||||
bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape,
|
||||
Node*& adr_src,
|
||||
Node*& base_src,
|
||||
@ -332,12 +345,11 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape,
|
||||
|
||||
Node* dest_scale = phase->transform(new LShiftXNode(dest_offset, phase->intcon(shift)));
|
||||
|
||||
adr_src = phase->transform(AddPNode::make_with_base(base_src, src_scale));
|
||||
adr_dest = phase->transform(AddPNode::make_with_base(base_dest, dest_scale));
|
||||
|
||||
adr_src = phase->transform(AddPNode::make_with_base(base_src, adr_src, phase->MakeConX(header)));
|
||||
adr_dest = phase->transform(AddPNode::make_with_base(base_dest, adr_dest, phase->MakeConX(header)));
|
||||
adr_src = make_and_transform_addp(phase, base_src, src_scale);
|
||||
adr_dest = make_and_transform_addp(phase, base_dest, dest_scale);
|
||||
|
||||
adr_src = make_and_transform_addp(phase, base_src, adr_src, phase->MakeConX(header));
|
||||
adr_dest = make_and_transform_addp(phase, base_dest, adr_dest, phase->MakeConX(header));
|
||||
copy_type = dest_elem;
|
||||
} else {
|
||||
assert(ary_src != nullptr, "should be a clone");
|
||||
@ -355,8 +367,8 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape,
|
||||
return false;
|
||||
}
|
||||
|
||||
adr_src = phase->transform(AddPNode::make_with_base(base_src, src_offset));
|
||||
adr_dest = phase->transform(AddPNode::make_with_base(base_dest, dest_offset));
|
||||
adr_src = make_and_transform_addp(phase, base_src, src_offset);
|
||||
adr_dest = make_and_transform_addp(phase, base_dest, dest_offset);
|
||||
|
||||
// The address is offsetted to an aligned address where a raw copy would start.
|
||||
// If the clone copy is decomposed into load-stores - the address is adjusted to
|
||||
@ -366,8 +378,8 @@ bool ArrayCopyNode::prepare_array_copy(PhaseGVN *phase, bool can_reshape,
|
||||
int diff = arrayOopDesc::base_offset_in_bytes(elem) - offset;
|
||||
assert(diff >= 0, "clone should not start after 1st array element");
|
||||
if (diff > 0) {
|
||||
adr_src = phase->transform(AddPNode::make_with_base(base_src, adr_src, phase->MakeConX(diff)));
|
||||
adr_dest = phase->transform(AddPNode::make_with_base(base_dest, adr_dest, phase->MakeConX(diff)));
|
||||
adr_src = make_and_transform_addp(phase, base_src, adr_src, phase->MakeConX(diff));
|
||||
adr_dest = make_and_transform_addp(phase, base_dest, adr_dest, phase->MakeConX(diff));
|
||||
}
|
||||
copy_type = elem;
|
||||
value_type = ary_src->elem();
|
||||
@ -429,12 +441,8 @@ Node* ArrayCopyNode::array_copy_forward(PhaseGVN *phase,
|
||||
store(bs, phase, forward_ctl, mm, adr_dest, atp_dest, v, value_type, copy_type);
|
||||
for (int i = 1; i < count; i++) {
|
||||
Node* off = phase->MakeConX(type2aelembytes(copy_type) * i);
|
||||
Node* next_src = phase->transform(AddPNode::make_with_base(base_src,adr_src,off));
|
||||
// We may have narrowed the type of next_src right before calling this method but because this runs with
|
||||
// PhaseIterGVN::_delay_transform true, explicitly update the type of the AddP so it's consistent with its
|
||||
// base and load() picks the right memory slice.
|
||||
phase->set_type(next_src, next_src->Value(phase));
|
||||
Node* next_dest = phase->transform(AddPNode::make_with_base(base_dest,adr_dest,off));
|
||||
Node* next_src = make_and_transform_addp(phase, base_src,adr_src,off);
|
||||
Node* next_dest = make_and_transform_addp(phase, base_dest,adr_dest,off);
|
||||
// Same as above
|
||||
phase->set_type(next_dest, next_dest->Value(phase));
|
||||
v = load(bs, phase, forward_ctl, mm, next_src, atp_src, value_type, copy_type);
|
||||
@ -473,13 +481,8 @@ Node* ArrayCopyNode::array_copy_backward(PhaseGVN *phase,
|
||||
if (count > 0) {
|
||||
for (int i = count-1; i >= 1; i--) {
|
||||
Node* off = phase->MakeConX(type2aelembytes(copy_type) * i);
|
||||
Node* next_src = phase->transform(AddPNode::make_with_base(base_src,adr_src,off));
|
||||
// We may have narrowed the type of next_src right before calling this method but because this runs with
|
||||
// PhaseIterGVN::_delay_transform true, explicitly update the type of the AddP so it's consistent with its
|
||||
// base and store() picks the right memory slice.
|
||||
phase->set_type(next_src, next_src->Value(phase));
|
||||
Node* next_dest = phase->transform(AddPNode::make_with_base(base_dest,adr_dest,off));
|
||||
phase->set_type(next_dest, next_dest->Value(phase));
|
||||
Node* next_src = make_and_transform_addp(phase, base_src,adr_src,off);
|
||||
Node* next_dest = make_and_transform_addp(phase, base_dest,adr_dest,off);
|
||||
Node* v = load(bs, phase, backward_ctl, mm, next_src, atp_src, value_type, copy_type);
|
||||
store(bs, phase, backward_ctl, mm, next_dest, atp_dest, v, value_type, copy_type);
|
||||
}
|
||||
@ -618,21 +621,31 @@ Node *ArrayCopyNode::Ideal(PhaseGVN *phase, bool can_reshape) {
|
||||
phase->set_type(src, phase->type(src)->join_speculative(atp_src));
|
||||
phase->set_type(dest, phase->type(dest)->join_speculative(atp_dest));
|
||||
|
||||
// Control flow is going to be created, it's easier to do with _delay_transform set to true.
|
||||
|
||||
// prepare_array_copy() doesn't build control flow, but it creates AddP nodes. The src/dest type possibly gets
|
||||
// narrowed above. If a newly created AddP node is commoned with a pre-existing one, then the type narrowing is lost.
|
||||
// Setting _delay_transform before prepare_array_copy() guarantees this doesn't happen.
|
||||
if (can_reshape) {
|
||||
assert(!phase->is_IterGVN()->delay_transform(), "cannot delay transforms");
|
||||
phase->is_IterGVN()->set_delay_transform(true);
|
||||
}
|
||||
|
||||
if (!prepare_array_copy(phase, can_reshape,
|
||||
adr_src, base_src, adr_dest, base_dest,
|
||||
copy_type, value_type, disjoint_bases)) {
|
||||
assert(adr_src == nullptr, "no node can be left behind");
|
||||
assert(adr_dest == nullptr, "no node can be left behind");
|
||||
if (can_reshape) {
|
||||
assert(phase->is_IterGVN()->delay_transform(), "cannot delay transforms");
|
||||
phase->is_IterGVN()->set_delay_transform(false);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Node* in_mem = in(TypeFunc::Memory);
|
||||
|
||||
if (can_reshape) {
|
||||
assert(!phase->is_IterGVN()->delay_transform(), "cannot delay transforms");
|
||||
phase->is_IterGVN()->set_delay_transform(true);
|
||||
}
|
||||
|
||||
Node* backward_ctl = phase->C->top();
|
||||
Node* forward_ctl = phase->C->top();
|
||||
array_copy_test_overlap(phase, can_reshape, disjoint_bases, count, forward_ctl, backward_ctl);
|
||||
|
||||
@ -104,6 +104,10 @@ private:
|
||||
static const TypePtr* get_address_type(PhaseGVN* phase, const TypePtr* atp, Node* n);
|
||||
|
||||
Node* try_clone_instance(PhaseGVN *phase, bool can_reshape, int count);
|
||||
|
||||
Node* make_and_transform_addp(PhaseGVN* phase, Node* base, Node* offset);
|
||||
Node* make_and_transform_addp(PhaseGVN* phase, Node* base, Node* ptr, Node* offset);
|
||||
|
||||
bool prepare_array_copy(PhaseGVN *phase, bool can_reshape,
|
||||
Node*& adr_src, Node*& base_src, Node*& adr_dest, Node*& base_dest,
|
||||
BasicType& copy_type, const Type*& value_type, bool& disjoint_bases);
|
||||
|
||||
@ -914,6 +914,44 @@
|
||||
\
|
||||
develop(bool, StressCountedLoop, false, \
|
||||
"Randomly delay conversion to counted loops") \
|
||||
\
|
||||
product(bool, HotCodeHeap, false, EXPERIMENTAL, \
|
||||
"Enable the code heap for hot C2 nmethods") \
|
||||
\
|
||||
product(double, HotCodeSamplePercent, 80, EXPERIMENTAL, \
|
||||
"Minimum percentage of profiling samples that must be in " \
|
||||
"the MethodHot heap before stopping hot code collection") \
|
||||
range(0, 100) \
|
||||
\
|
||||
product(double, HotCodeStablePercent, 5, EXPERIMENTAL, \
|
||||
"Maximum percentage of newly compiled to total C2 nmethods " \
|
||||
"to treat nmethod count as stable. " \
|
||||
"Values less than zero disable the stable check") \
|
||||
range(-1, DBL_MAX) \
|
||||
\
|
||||
product(uint, HotCodeIntervalSeconds, 300, EXPERIMENTAL, \
|
||||
"Seconds between hot code grouping attempts") \
|
||||
range(0, max_juint) \
|
||||
\
|
||||
product(uint, HotCodeSampleSeconds, 120, EXPERIMENTAL, \
|
||||
"Seconds to sample application threads per grouping attempt") \
|
||||
range(0, max_juint) \
|
||||
\
|
||||
product(uint, HotCodeStartupDelaySeconds, 120, EXPERIMENTAL, \
|
||||
"Seconds to delay before starting hot code grouping thread") \
|
||||
range(0, max_juint) \
|
||||
\
|
||||
product(uint, HotCodeMinSamplingMs, 5, EXPERIMENTAL, \
|
||||
"Minimum sampling interval in milliseconds") \
|
||||
range(0, max_juint) \
|
||||
\
|
||||
product(uint, HotCodeMaxSamplingMs, 15, EXPERIMENTAL, \
|
||||
"Maximum sampling interval in milliseconds") \
|
||||
range(0, max_juint) \
|
||||
\
|
||||
product(uint, HotCodeCallLevel, 1, EXPERIMENTAL, \
|
||||
"Number of levels of callees to relocate per candidate") \
|
||||
range(0, max_juint) \
|
||||
|
||||
// end of C2_FLAGS
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ enum class vmIntrinsicID;
|
||||
} \
|
||||
} else if (Use##feature) { \
|
||||
if (!FLAG_IS_DEFAULT(Use##feature)) { \
|
||||
warning(#feature " instructions not available on this CPU"); \
|
||||
warning(#feature " instructions are not available on this CPU"); \
|
||||
} \
|
||||
FLAG_SET_DEFAULT(Use##feature, false); \
|
||||
}
|
||||
|
||||
@ -1514,6 +1514,10 @@ const int ObjectAlignmentInBytes = 8;
|
||||
"Size of code heap with non-nmethods (in bytes)") \
|
||||
constraint(VMPageSizeConstraintFunc, AtParse) \
|
||||
\
|
||||
product(size_t, HotCodeHeapSize, 0, EXPERIMENTAL, \
|
||||
"Size of code heap with predicted hot methods (in bytes)") \
|
||||
range(0, SIZE_MAX) \
|
||||
\
|
||||
product_pd(size_t, CodeCacheExpansionSize, \
|
||||
"Code cache expansion size (in bytes)") \
|
||||
range(32*K, SIZE_MAX) \
|
||||
|
||||
258
src/hotspot/share/runtime/hotCodeCollector.cpp
Normal file
258
src/hotspot/share/runtime/hotCodeCollector.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef COMPILER2
|
||||
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "compiler/compilerDefinitions.inline.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "runtime/hotCodeCollector.hpp"
|
||||
#include "runtime/hotCodeSampler.hpp"
|
||||
#include "runtime/java.hpp"
|
||||
#include "runtime/javaThread.inline.hpp"
|
||||
|
||||
// Initialize static variables
|
||||
bool HotCodeCollector::_is_initialized = false;
|
||||
int HotCodeCollector::_new_c2_nmethods_count = 0;
|
||||
int HotCodeCollector::_total_c2_nmethods_count = 0;
|
||||
|
||||
HotCodeCollector::HotCodeCollector() : JavaThread(thread_entry) {}
|
||||
|
||||
void HotCodeCollector::initialize() {
|
||||
EXCEPTION_MARK;
|
||||
|
||||
assert(HotCodeHeap, "HotCodeCollector requires HotCodeHeap enabled");
|
||||
assert(CompilerConfig::is_c2_enabled(), "HotCodeCollector requires C2 enabled");
|
||||
assert(NMethodRelocation, "HotCodeCollector requires NMethodRelocation enabled");
|
||||
assert(HotCodeHeapSize > 0, "HotCodeHeapSize must be non-zero to use HotCodeCollector");
|
||||
assert(CodeCache::get_code_heap(CodeBlobType::MethodHot) != nullptr, "MethodHot code heap not found");
|
||||
|
||||
Handle thread_oop = JavaThread::create_system_thread_object("HotCodeCollectorThread", CHECK);
|
||||
HotCodeCollector* thread = new HotCodeCollector();
|
||||
JavaThread::vm_exit_on_osthread_failure(thread);
|
||||
JavaThread::start_internal_daemon(THREAD, thread, thread_oop, NormPriority);
|
||||
|
||||
_is_initialized = true;
|
||||
}
|
||||
|
||||
bool HotCodeCollector::is_nmethod_count_stable() {
|
||||
if (HotCodeStablePercent < 0) {
|
||||
log_info(hotcode)("HotCodeStablePercent is less than zero, stable check disabled");
|
||||
return true;
|
||||
}
|
||||
|
||||
MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
||||
if (_total_c2_nmethods_count <= 0) {
|
||||
log_info(hotcode)("No registered C2 nmethods");
|
||||
return false;
|
||||
}
|
||||
|
||||
const double percent_new = 100.0 * _new_c2_nmethods_count / _total_c2_nmethods_count;
|
||||
bool is_stable_nmethod_count = percent_new <= HotCodeStablePercent;
|
||||
|
||||
log_info(hotcode)("C2 nmethod count %s", is_stable_nmethod_count ? "stable" : "not stable");
|
||||
log_debug(hotcode)("C2 nmethod stats: New: %d, Total: %d, Percent new: %f", _new_c2_nmethods_count, _total_c2_nmethods_count, percent_new);
|
||||
|
||||
_new_c2_nmethods_count = 0;
|
||||
|
||||
return is_stable_nmethod_count;
|
||||
}
|
||||
|
||||
void HotCodeCollector::thread_entry(JavaThread* thread, TRAPS) {
|
||||
// Initial sleep to allow JVM to warm up
|
||||
thread->sleep(HotCodeStartupDelaySeconds * 1000);
|
||||
|
||||
while (true) {
|
||||
ResourceMark rm;
|
||||
|
||||
// Sample application and group hot nmethods if nmethod count is stable
|
||||
if (is_nmethod_count_stable()) {
|
||||
log_info(hotcode)("Sampling...");
|
||||
|
||||
ThreadSampler sampler;
|
||||
uint64_t start_time = os::javaTimeMillis();
|
||||
while (os::javaTimeMillis() - start_time <= HotCodeSampleSeconds * 1000) {
|
||||
sampler.sample_all_java_threads();
|
||||
thread->sleep(rand_sampling_period_ms());
|
||||
}
|
||||
|
||||
Candidates candidates(sampler);
|
||||
do_grouping(candidates);
|
||||
}
|
||||
|
||||
thread->sleep(HotCodeIntervalSeconds * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
void HotCodeCollector::do_grouping(Candidates& candidates) {
|
||||
int num_relocated = 0;
|
||||
|
||||
// Sort nmethods by increasing sample count so pop() returns the hottest
|
||||
candidates.sort();
|
||||
|
||||
while (candidates.has_candidates()) {
|
||||
|
||||
double percent_from_hot = candidates.get_hot_sample_percent();
|
||||
log_debug(hotcode)("Percentage of samples from hot code heap: %f", percent_from_hot);
|
||||
if (percent_from_hot >= HotCodeSamplePercent) {
|
||||
log_info(hotcode)("Percentage of samples from hot nmethods over threshold. Done collecting hot code");
|
||||
break;
|
||||
}
|
||||
|
||||
nmethod* candidate = candidates.get_candidate();
|
||||
|
||||
MutexLocker ml_Compile_lock(Compile_lock);
|
||||
MutexLocker ml_CompiledIC_lock(CompiledIC_lock, Mutex::_no_safepoint_check_flag);
|
||||
MutexLocker ml_CodeCache_lock(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
||||
num_relocated += do_relocation(candidate, 0);
|
||||
}
|
||||
|
||||
log_info(hotcode)("Collection done. Relocated %d nmethods to the MethodHot heap", num_relocated);
|
||||
}
|
||||
|
||||
int HotCodeCollector::do_relocation(void* candidate, uint call_level) {
|
||||
if (candidate == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Verify that address still points to CodeBlob
|
||||
CodeBlob* blob = CodeCache::find_blob(candidate);
|
||||
if (blob == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Verify that blob is nmethod
|
||||
nmethod* nm = blob->as_nmethod_or_null();
|
||||
if (nm == nullptr || nm->method() == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The candidate may have been recompiled or already relocated.
|
||||
// Retrieve the latest nmethod from the Method
|
||||
nm = nm->method()->code();
|
||||
|
||||
// Verify the nmethod is still valid for relocation
|
||||
if (nm == nullptr || !nm->is_in_use() || !nm->is_compiled_by_c2()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Verify code heap has space
|
||||
if (CodeCache::get_code_heap(CodeBlobType::MethodHot)->unallocated_capacity() < (size_t)nm->size()) {
|
||||
log_info(hotcode)("Not enough free space in MethodHot heap (%zd bytes) to relocate nm (%d bytes). Bailing out",
|
||||
CodeCache::get_code_heap(CodeBlobType::MethodHot)->unallocated_capacity(), nm->size());
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Number of nmethods relocated (candidate + callees)
|
||||
int num_relocated = 0;
|
||||
|
||||
// Pointer to nmethod in hot heap
|
||||
nmethod* hot_nm = nullptr;
|
||||
|
||||
if (CodeCache::get_code_blob_type(nm) != CodeBlobType::MethodHot) {
|
||||
CompiledICLocker ic_locker(nm);
|
||||
hot_nm = nm->relocate(CodeBlobType::MethodHot);
|
||||
|
||||
if (hot_nm != nullptr) {
|
||||
// Successfully relocated nmethod. Update counts and proceed to callee relocation.
|
||||
log_debug(hotcode)("Successful relocation: nmethod (%p), method (%s), call level (%d)", nm, hot_nm->method()->name_and_sig_as_C_string(), call_level);
|
||||
num_relocated++;
|
||||
} else {
|
||||
// Relocation failed so return and do not attempt to relocate callees
|
||||
log_debug(hotcode)("Failed relocation: nmethod (%p), call level (%d)", nm, call_level);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
// Skip relocation since already in hot heap, but still relocate callees
|
||||
// since they may not have been compiled when this method was first relocated
|
||||
log_debug(hotcode)("Already relocated: nmethod (%p), method (%s), call level (%d)", nm, nm->method()->name_and_sig_as_C_string(), call_level);
|
||||
hot_nm = nm;
|
||||
}
|
||||
|
||||
assert(hot_nm != nullptr, "unable to relocate callees");
|
||||
|
||||
if (call_level < HotCodeCallLevel) {
|
||||
// Loop over relocations to relocate callees
|
||||
RelocIterator relocIter(hot_nm);
|
||||
while (relocIter.next()) {
|
||||
// Check if this is a call
|
||||
Relocation* reloc = relocIter.reloc();
|
||||
if (!reloc->is_call()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the call destination address
|
||||
address dest = ((CallRelocation*) reloc)->destination();
|
||||
|
||||
// Recursively relocate callees
|
||||
num_relocated += do_relocation(dest, call_level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return num_relocated;
|
||||
}
|
||||
|
||||
void HotCodeCollector::unregister_nmethod(nmethod* nm) {
|
||||
assert_lock_strong(CodeCache_lock);
|
||||
if (!_is_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nm->is_compiled_by_c2()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (CodeCache::get_code_blob_type(nm) == CodeBlobType::MethodHot) {
|
||||
// Nmethods in the hot code heap do not count towards total C2 nmethods.
|
||||
return;
|
||||
}
|
||||
|
||||
// CodeCache_lock is held, so we can safely decrement the count.
|
||||
_total_c2_nmethods_count--;
|
||||
}
|
||||
|
||||
void HotCodeCollector::register_nmethod(nmethod* nm) {
|
||||
assert_lock_strong(CodeCache_lock);
|
||||
if (!_is_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!nm->is_compiled_by_c2()) {
|
||||
return; // Only C2 nmethods are relocated to HotCodeHeap.
|
||||
}
|
||||
|
||||
if (CodeCache::get_code_blob_type(nm) == CodeBlobType::MethodHot) {
|
||||
// Nmethods in the hot code heap do not count towards total C2 nmethods.
|
||||
return;
|
||||
}
|
||||
|
||||
// CodeCache_lock is held, so we can safely increment the count.
|
||||
_new_c2_nmethods_count++;
|
||||
_total_c2_nmethods_count++;
|
||||
}
|
||||
#endif // COMPILER2
|
||||
56
src/hotspot/share/runtime/hotCodeCollector.hpp
Normal file
56
src/hotspot/share/runtime/hotCodeCollector.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef COMPILER2
|
||||
#ifndef SHARE_RUNTIME_HOTCODECOLLECTOR_HPP
|
||||
#define SHARE_RUNTIME_HOTCODECOLLECTOR_HPP
|
||||
|
||||
#include "runtime/javaThread.hpp"
|
||||
|
||||
class Candidates;
|
||||
|
||||
class HotCodeCollector : public JavaThread {
|
||||
private:
|
||||
static bool _is_initialized;
|
||||
|
||||
static int _new_c2_nmethods_count;
|
||||
static int _total_c2_nmethods_count;
|
||||
|
||||
HotCodeCollector();
|
||||
|
||||
static void do_grouping(Candidates& candidates);
|
||||
|
||||
static int do_relocation(void* candidate, uint call_level);
|
||||
|
||||
public:
|
||||
static void initialize();
|
||||
static void thread_entry(JavaThread* thread, TRAPS);
|
||||
static void unregister_nmethod(nmethod* nm);
|
||||
static void register_nmethod(nmethod* nm);
|
||||
|
||||
static bool is_nmethod_count_stable();
|
||||
};
|
||||
|
||||
#endif // SHARE_RUNTIME_HOTCODECOLLECTOR_HPP
|
||||
#endif // COMPILER2
|
||||
121
src/hotspot/share/runtime/hotCodeSampler.cpp
Normal file
121
src/hotspot/share/runtime/hotCodeSampler.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef COMPILER2
|
||||
|
||||
#include "code/codeCache.hpp"
|
||||
#include "logging/log.hpp"
|
||||
#include "runtime/hotCodeSampler.hpp"
|
||||
#include "runtime/javaThread.inline.hpp"
|
||||
|
||||
void ThreadSampler::sample_all_java_threads() {
|
||||
// Collect samples for each JavaThread
|
||||
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
|
||||
if (jt->is_hidden_from_external_view() ||
|
||||
jt->in_deopt_handler() ||
|
||||
(jt->thread_state() != _thread_in_native && jt->thread_state() != _thread_in_Java)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
GetPCTask task(jt);
|
||||
task.run();
|
||||
address pc = task.pc();
|
||||
if (pc == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CodeCache::contains(pc)) {
|
||||
nmethod* nm = CodeCache::find_blob(pc)->as_nmethod_or_null();
|
||||
if (nm != nullptr) {
|
||||
bool created = false;
|
||||
int *count = _samples.put_if_absent(nm, 0, &created);
|
||||
(*count)++;
|
||||
if (created) {
|
||||
_samples.maybe_grow();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Candidates::Candidates(ThreadSampler& sampler)
|
||||
: _hot_sample_count(0), _non_profiled_sample_count(0) {
|
||||
auto func = [&](nmethod* nm, int count) {
|
||||
if (CodeCache::get_code_blob_type(nm) == CodeBlobType::MethodNonProfiled) {
|
||||
_candidates.append(Pair<nmethod*, int>(nm, count));
|
||||
add_non_profiled_sample_count(count);
|
||||
} else if (CodeCache::get_code_blob_type(nm) == CodeBlobType::MethodHot) {
|
||||
add_hot_sample_count(count);
|
||||
}
|
||||
};
|
||||
sampler.iterate_samples(func);
|
||||
|
||||
log_info(hotcode)("Generated candidate list from %d samples corresponding to %d nmethods", _non_profiled_sample_count + _hot_sample_count, _candidates.length());
|
||||
}
|
||||
|
||||
void Candidates::add_candidate(nmethod* nm, int count) {
|
||||
_candidates.append(Pair<nmethod*, int>(nm, count));
|
||||
}
|
||||
|
||||
void Candidates::add_hot_sample_count(int count) {
|
||||
_hot_sample_count += count;
|
||||
}
|
||||
|
||||
void Candidates::add_non_profiled_sample_count(int count) {
|
||||
_non_profiled_sample_count += count;
|
||||
}
|
||||
|
||||
void Candidates::sort() {
|
||||
_candidates.sort(
|
||||
[](Pair<nmethod*, int>* a, Pair<nmethod*, int>* b) {
|
||||
if (a->second > b->second) return 1;
|
||||
if (a->second < b->second) return -1;
|
||||
return 0;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
bool Candidates::has_candidates() {
|
||||
return !_candidates.is_empty();
|
||||
}
|
||||
|
||||
nmethod* Candidates::get_candidate() {
|
||||
assert(has_candidates(), "must not be empty");
|
||||
Pair<nmethod*, int> candidate = _candidates.pop();
|
||||
|
||||
_hot_sample_count += candidate.second;
|
||||
_non_profiled_sample_count -= candidate.second;
|
||||
|
||||
return candidate.first;
|
||||
}
|
||||
|
||||
double Candidates::get_hot_sample_percent() {
|
||||
if (_hot_sample_count + _non_profiled_sample_count == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 100.0 * _hot_sample_count / (_hot_sample_count + _non_profiled_sample_count);
|
||||
}
|
||||
|
||||
#endif // COMPILER2
|
||||
104
src/hotspot/share/runtime/hotCodeSampler.hpp
Normal file
104
src/hotspot/share/runtime/hotCodeSampler.hpp
Normal file
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef COMPILER2
|
||||
#ifndef SHARE_RUNTIME_HOTCODESAMPLER_HPP
|
||||
#define SHARE_RUNTIME_HOTCODESAMPLER_HPP
|
||||
|
||||
#include "runtime/javaThread.hpp"
|
||||
#include "runtime/suspendedThreadTask.hpp"
|
||||
#include "runtime/threadSMR.hpp"
|
||||
#include "utilities/pair.hpp"
|
||||
#include "utilities/resizableHashTable.hpp"
|
||||
|
||||
// Generate a random sampling period between min and max
|
||||
static inline uint rand_sampling_period_ms() {
|
||||
assert(HotCodeMaxSamplingMs >= HotCodeMinSamplingMs, "max cannot be smaller than min");
|
||||
julong range = (julong)HotCodeMaxSamplingMs - (julong)HotCodeMinSamplingMs + 1;
|
||||
return (uint)(os::random() % range) + HotCodeMinSamplingMs;
|
||||
}
|
||||
|
||||
class ThreadSampler;
|
||||
|
||||
class Candidates : public StackObj {
|
||||
private:
|
||||
GrowableArray<Pair<nmethod*, int>> _candidates;
|
||||
int _hot_sample_count;
|
||||
int _non_profiled_sample_count;
|
||||
|
||||
public:
|
||||
Candidates(ThreadSampler& sampler);
|
||||
|
||||
void add_candidate(nmethod* nm, int count);
|
||||
void add_hot_sample_count(int count);
|
||||
void add_non_profiled_sample_count(int count);
|
||||
void sort();
|
||||
|
||||
bool has_candidates();
|
||||
nmethod* get_candidate();
|
||||
double get_hot_sample_percent();
|
||||
};
|
||||
|
||||
class GetPCTask : public SuspendedThreadTask {
|
||||
private:
|
||||
address _pc;
|
||||
|
||||
void do_task(const SuspendedThreadTaskContext& context) override {
|
||||
JavaThread* jt = JavaThread::cast(context.thread());
|
||||
if (jt->thread_state() != _thread_in_native && jt->thread_state() != _thread_in_Java) {
|
||||
return;
|
||||
}
|
||||
_pc = os::fetch_frame_from_context(context.ucontext(), nullptr, nullptr);
|
||||
}
|
||||
|
||||
public:
|
||||
GetPCTask(JavaThread* thread) : SuspendedThreadTask(thread), _pc(nullptr) {}
|
||||
|
||||
address pc() const {
|
||||
return _pc;
|
||||
}
|
||||
};
|
||||
|
||||
class ThreadSampler : public StackObj {
|
||||
private:
|
||||
static const int INITIAL_TABLE_SIZE = 109;
|
||||
|
||||
// Table of nmethods found during profiling with sample count
|
||||
ResizeableHashTable<nmethod*, int, AnyObj::C_HEAP, mtInternal> _samples;
|
||||
|
||||
public:
|
||||
ThreadSampler() : _samples(INITIAL_TABLE_SIZE, HotCodeSampleSeconds * 1000 / HotCodeMaxSamplingMs) {}
|
||||
|
||||
// Iterate over and sample all Java threads
|
||||
void sample_all_java_threads();
|
||||
|
||||
// Iterate over all samples with a callback function
|
||||
template<typename Function>
|
||||
void iterate_samples(Function func) {
|
||||
_samples.iterate_all(func);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_RUNTIME_HOTCODESAMPLER_HPP
|
||||
#endif // COMPILER2
|
||||
@ -113,6 +113,7 @@
|
||||
#endif
|
||||
#ifdef COMPILER2
|
||||
#include "opto/idealGraphPrinter.hpp"
|
||||
#include "runtime/hotCodeCollector.hpp"
|
||||
#endif
|
||||
#if INCLUDE_JFR
|
||||
#include "jfr/jfr.hpp"
|
||||
@ -798,6 +799,12 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
|
||||
StringDedup::start();
|
||||
}
|
||||
|
||||
#ifdef COMPILER2
|
||||
if (HotCodeHeap) {
|
||||
HotCodeCollector::initialize();
|
||||
}
|
||||
#endif // COMPILER2
|
||||
|
||||
// Pre-initialize some JSR292 core classes to avoid deadlock during class loading.
|
||||
// It is done after compilers are initialized, because otherwise compilations of
|
||||
// signature polymorphic MH intrinsics can be missed
|
||||
|
||||
@ -1327,13 +1327,13 @@ void VMError::report(outputStream* st, bool _verbose) {
|
||||
|
||||
STEP_IF("printing OS information", _verbose)
|
||||
os::print_os_info(st);
|
||||
st->cr();
|
||||
#ifdef __APPLE__
|
||||
// Avoid large stack allocation on Mac for FD count during signal-handling.
|
||||
os::Bsd::print_open_file_descriptors(st, buf, sizeof(buf));
|
||||
st->cr();
|
||||
#else
|
||||
os::print_open_file_descriptors(st);
|
||||
st->cr();
|
||||
#endif
|
||||
|
||||
STEP_IF("printing CPU info", _verbose)
|
||||
@ -1553,7 +1553,6 @@ void VMError::print_vm_info(outputStream* st) {
|
||||
// STEP("printing OS information")
|
||||
|
||||
os::print_os_info(st);
|
||||
st->cr();
|
||||
os::print_open_file_descriptors(st);
|
||||
st->cr();
|
||||
|
||||
|
||||
@ -70,9 +70,9 @@ import sun.nio.cs.UTF_8;
|
||||
* string literals in Java programs, such as {@code "abc"}, are
|
||||
* implemented as instances of this class.
|
||||
* <p>
|
||||
* Strings are constant; their values cannot be changed after they
|
||||
* are created. String buffers support mutable strings.
|
||||
* Because String objects are immutable they can be shared. For example:
|
||||
* Strings are immutable; their values cannot be changed after they
|
||||
* are created. Because String objects are immutable they can be shared.
|
||||
* For example:
|
||||
* <blockquote><pre>
|
||||
* String str = "abc";
|
||||
* </pre></blockquote><p>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -41,7 +41,7 @@ package java.text;
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import static java.text.DateFormatSymbols.*;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
@ -57,6 +57,8 @@ import sun.util.calendar.ZoneInfoFile;
|
||||
import sun.util.locale.provider.LocaleProviderAdapter;
|
||||
import sun.util.locale.provider.TimeZoneNameUtility;
|
||||
|
||||
import static java.text.DateFormatSymbols.*;
|
||||
|
||||
/**
|
||||
* {@code SimpleDateFormat} is a concrete class for formatting and
|
||||
* parsing dates in a locale-sensitive manner. It allows for formatting
|
||||
@ -1293,15 +1295,22 @@ public class SimpleDateFormat extends DateFormat {
|
||||
|
||||
case PATTERN_ZONE_NAME: // 'z'
|
||||
if (current == null) {
|
||||
TimeZone tz = calendar.getTimeZone();
|
||||
String tzid = tz.getID();
|
||||
int zoneOffset = calendar.get(Calendar.ZONE_OFFSET);
|
||||
int dstOffset = calendar.get(Calendar.DST_OFFSET) + zoneOffset;
|
||||
|
||||
// Check if an explicit metazone DST offset exists
|
||||
String explicitDstOffset = TimeZoneNameUtility.explicitDstOffset(tzid);
|
||||
boolean daylight = explicitDstOffset != null ?
|
||||
dstOffset == ZoneOffset.of(explicitDstOffset).getTotalSeconds() * 1_000 :
|
||||
dstOffset != zoneOffset;
|
||||
if (formatData.locale == null || formatData.isZoneStringsSet) {
|
||||
int zoneIndex =
|
||||
formatData.getZoneIndex(calendar.getTimeZone().getID());
|
||||
int zoneIndex = formatData.getZoneIndex(tzid);
|
||||
if (zoneIndex == -1) {
|
||||
value = calendar.get(Calendar.ZONE_OFFSET) +
|
||||
calendar.get(Calendar.DST_OFFSET);
|
||||
buffer.append(ZoneInfoFile.toCustomID(value));
|
||||
buffer.append(ZoneInfoFile.toCustomID(dstOffset));
|
||||
} else {
|
||||
int index = (calendar.get(Calendar.DST_OFFSET) == 0) ? 1: 3;
|
||||
int index = daylight ? 3 : 1;
|
||||
if (count < 4) {
|
||||
// Use the short name
|
||||
index++;
|
||||
@ -1310,8 +1319,6 @@ public class SimpleDateFormat extends DateFormat {
|
||||
buffer.append(zoneStrings[zoneIndex][index]);
|
||||
}
|
||||
} else {
|
||||
TimeZone tz = calendar.getTimeZone();
|
||||
boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
|
||||
int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG);
|
||||
buffer.append(tz.getDisplayName(daylight, tzstyle, formatData.locale));
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2025, Alibaba Group Holding Limited. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -4513,7 +4513,11 @@ public final class DateTimeFormatterBuilder {
|
||||
TemporalAccessor dt = context.getTemporal();
|
||||
int type = GENERIC;
|
||||
if (!isGeneric) {
|
||||
if (dt.isSupported(ChronoField.INSTANT_SECONDS)) {
|
||||
// Check if an explicit metazone DST offset exists
|
||||
String dstOffset = TimeZoneNameUtility.explicitDstOffset(zname);
|
||||
if (dt.isSupported(OFFSET_SECONDS) && dstOffset != null) {
|
||||
type = ZoneOffset.from(dt).equals(ZoneOffset.of(dstOffset)) ? DST : STD;
|
||||
} else if (dt.isSupported(ChronoField.INSTANT_SECONDS)) {
|
||||
type = zone.getRules().isDaylightSavings(Instant.from(dt)) ? DST : STD;
|
||||
} else if (dt.isSupported(ChronoField.EPOCH_DAY) &&
|
||||
dt.isSupported(ChronoField.NANO_OF_DAY)) {
|
||||
|
||||
@ -1932,7 +1932,7 @@ public final class Locale implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the locale's language that is appropriate for display to the
|
||||
* Returns a name for {@code this} locale's language that is appropriate for display to the
|
||||
* user.
|
||||
* If possible, the name returned will be localized for the default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale.
|
||||
@ -1946,14 +1946,15 @@ public final class Locale implements Cloneable, Serializable {
|
||||
* this function falls back on the English name, and uses the ISO code as a last-resort
|
||||
* value. If the locale doesn't specify a language, this function returns the empty string.
|
||||
*
|
||||
* @return The name of the display language.
|
||||
* @return The name of the display language appropriate to the default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale.
|
||||
*/
|
||||
public final String getDisplayLanguage() {
|
||||
public String getDisplayLanguage() {
|
||||
return getDisplayLanguage(getDefault(Category.DISPLAY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the locale's language that is appropriate for display to the
|
||||
* Returns a name for {@code this} locale's language that is appropriate for display to the
|
||||
* user.
|
||||
* If possible, the name returned will be localized according to inLocale.
|
||||
* For example, if the locale is fr_FR and inLocale
|
||||
@ -1964,7 +1965,7 @@ public final class Locale implements Cloneable, Serializable {
|
||||
* on the ISO code as a last-resort value. If the locale doesn't specify a language,
|
||||
* this function returns the empty string.
|
||||
*
|
||||
* @param inLocale The locale for which to retrieve the display language.
|
||||
* @param inLocale The locale in which to localize the display language.
|
||||
* @return The name of the display language appropriate to the given locale.
|
||||
* @throws NullPointerException if {@code inLocale} is {@code null}
|
||||
*/
|
||||
@ -1973,13 +1974,13 @@ public final class Locale implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the locale's script that is appropriate for display to
|
||||
* Returns a name for {@code this} locale's script that is appropriate for display to
|
||||
* the user. If possible, the name will be localized for the default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale. Returns
|
||||
* the empty string if this locale doesn't specify a script code.
|
||||
*
|
||||
* @return the display name of the script code for the current default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale
|
||||
* @return The display name of the script code appropriate to the default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale.
|
||||
* @since 1.7
|
||||
*/
|
||||
public String getDisplayScript() {
|
||||
@ -1987,14 +1988,13 @@ public final class Locale implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the locale's script that is appropriate
|
||||
* Returns a name for {@code this} locale's script that is appropriate
|
||||
* for display to the user. If possible, the name will be
|
||||
* localized for the given locale. Returns the empty string if
|
||||
* this locale doesn't specify a script code.
|
||||
*
|
||||
* @param inLocale The locale for which to retrieve the display script.
|
||||
* @return the display name of the script code for the current default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale
|
||||
* @param inLocale The locale in which to localize the display script.
|
||||
* @return The display name of the script code appropriate to the given locale.
|
||||
* @throws NullPointerException if {@code inLocale} is {@code null}
|
||||
* @since 1.7
|
||||
*/
|
||||
@ -2003,7 +2003,7 @@ public final class Locale implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the locale's country that is appropriate for display to the
|
||||
* Returns a name for {@code this} locale's country that is appropriate for display to the
|
||||
* user.
|
||||
* If possible, the name returned will be localized for the default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale.
|
||||
@ -2017,14 +2017,15 @@ public final class Locale implements Cloneable, Serializable {
|
||||
* this function falls back on the English name, and uses the ISO code as a last-resort
|
||||
* value. If the locale doesn't specify a country, this function returns the empty string.
|
||||
*
|
||||
* @return The name of the country appropriate to the locale.
|
||||
* @return The name of the country appropriate to the default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale.
|
||||
*/
|
||||
public final String getDisplayCountry() {
|
||||
public String getDisplayCountry() {
|
||||
return getDisplayCountry(getDefault(Category.DISPLAY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the locale's country that is appropriate for display to the
|
||||
* Returns a name for {@code this} locale's country that is appropriate for display to the
|
||||
* user.
|
||||
* If possible, the name returned will be localized according to inLocale.
|
||||
* For example, if the locale is fr_FR and inLocale
|
||||
@ -2035,7 +2036,7 @@ public final class Locale implements Cloneable, Serializable {
|
||||
* on the ISO code as a last-resort value. If the locale doesn't specify a country,
|
||||
* this function returns the empty string.
|
||||
*
|
||||
* @param inLocale The locale for which to retrieve the display country.
|
||||
* @param inLocale The locale in which to localize the display country.
|
||||
* @return The name of the country appropriate to the given locale.
|
||||
* @throws NullPointerException if {@code inLocale} is {@code null}
|
||||
*/
|
||||
@ -2061,23 +2062,24 @@ public final class Locale implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the locale's variant code that is appropriate for display to the
|
||||
* Returns a name for {@code this} locale's variant code that is appropriate for display to the
|
||||
* user. If possible, the name will be localized for the default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale. If the locale
|
||||
* doesn't specify a variant code, this function returns the empty string.
|
||||
*
|
||||
* @return The name of the display variant code appropriate to the locale.
|
||||
* @return The name of the display variant code appropriate to the default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale.
|
||||
*/
|
||||
public final String getDisplayVariant() {
|
||||
public String getDisplayVariant() {
|
||||
return getDisplayVariant(getDefault(Category.DISPLAY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the locale's variant code that is appropriate for display to the
|
||||
* Returns a name for {@code this} locale's variant code that is appropriate for display to the
|
||||
* user. If possible, the name will be localized for inLocale. If the locale
|
||||
* doesn't specify a variant code, this function returns the empty string.
|
||||
*
|
||||
* @param inLocale The locale for which to retrieve the display variant code.
|
||||
* @param inLocale The locale in which to localize the display variant code.
|
||||
* @return The name of the display variant code appropriate to the given locale.
|
||||
* @throws NullPointerException if {@code inLocale} is {@code null}
|
||||
*/
|
||||
@ -2098,7 +2100,7 @@ public final class Locale implements Cloneable, Serializable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the locale that is appropriate for display to the
|
||||
* Returns a name for {@code this} locale that is appropriate for display to the
|
||||
* user. This will be the values returned by getDisplayLanguage(),
|
||||
* getDisplayScript(), getDisplayCountry(), getDisplayVariant() and
|
||||
* optional {@linkplain ##def_locale_extension Unicode extensions}
|
||||
@ -2116,14 +2118,15 @@ public final class Locale implements Cloneable, Serializable {
|
||||
* be localized depending on the locale. If the language, script, country,
|
||||
* and variant fields are all empty, this function returns the empty string.
|
||||
*
|
||||
* @return The name of the locale appropriate to display.
|
||||
* @return The display name appropriate to the default
|
||||
* {@link Locale.Category#DISPLAY DISPLAY} locale.
|
||||
*/
|
||||
public final String getDisplayName() {
|
||||
public String getDisplayName() {
|
||||
return getDisplayName(getDefault(Category.DISPLAY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a name for the locale that is appropriate for display
|
||||
* Returns a name for {@code this} locale that is appropriate for display
|
||||
* to the user. This will be the values returned by
|
||||
* getDisplayLanguage(), getDisplayScript(), getDisplayCountry(),
|
||||
* getDisplayVariant(), and optional {@linkplain ##def_locale_extension
|
||||
@ -2142,8 +2145,8 @@ public final class Locale implements Cloneable, Serializable {
|
||||
* be localized depending on the locale. If the language, script, country,
|
||||
* and variant fields are all empty, this function returns the empty string.
|
||||
*
|
||||
* @param inLocale The locale for which to retrieve the display name.
|
||||
* @return The name of the locale appropriate to display.
|
||||
* @param inLocale The locale in which to localize the display name.
|
||||
* @return The display name appropriate to the given locale.
|
||||
* @throws NullPointerException if {@code inLocale} is {@code null}
|
||||
*/
|
||||
public String getDisplayName(Locale inLocale) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -651,8 +651,9 @@ public class ZipEntry implements ZipConstants, Cloneable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional comment string for the entry.
|
||||
* @param comment the comment string
|
||||
* Sets the optional comment string for the entry. If {@code comment} is an
|
||||
* empty string or {@code null} then the entry will have no comment.
|
||||
* @param comment the comment string, or an empty string or null for no comment
|
||||
* @throws IllegalArgumentException if the combined length
|
||||
* of the specified entry comment, the {@linkplain #getName() entry name},
|
||||
* the {@linkplain #getExtra() extra field data}, and the
|
||||
|
||||
@ -43,6 +43,10 @@ import sun.nio.cs.UTF_8;
|
||||
* <p> Unless otherwise noted, passing a {@code null} argument to a constructor
|
||||
* or method in this class will cause a {@link NullPointerException} to be
|
||||
* thrown.
|
||||
* <p> By default, the UTF-8 charset is used to encode entry names and comments.
|
||||
* {@link #ZipOutputStream(OutputStream, Charset)} may be be used to specify
|
||||
* an alternative charset.
|
||||
*
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
@ -110,10 +114,8 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
|
||||
public static final int DEFLATED = ZipEntry.DEFLATED;
|
||||
|
||||
/**
|
||||
* Creates a new ZIP output stream.
|
||||
*
|
||||
* <p>The UTF-8 {@link java.nio.charset.Charset charset} is used
|
||||
* to encode the entry names and comments.
|
||||
* Creates a new ZIP output stream using the UTF-8
|
||||
* {@link Charset charset} to encode entry names and comments.
|
||||
*
|
||||
* @param out the actual output stream
|
||||
*/
|
||||
@ -122,12 +124,13 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ZIP output stream.
|
||||
* Creates a new ZIP output stream using the specified
|
||||
* {@link Charset charset} to encode entry names and comments.
|
||||
*
|
||||
* @param out the actual output stream
|
||||
*
|
||||
* @param charset the {@linkplain java.nio.charset.Charset charset}
|
||||
* to be used to encode the entry names and comments
|
||||
* to be used to encode entry names and comments
|
||||
*
|
||||
* @since 1.7
|
||||
*/
|
||||
@ -140,10 +143,15 @@ public class ZipOutputStream extends DeflaterOutputStream implements ZipConstant
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ZIP file comment.
|
||||
* @param comment the comment string
|
||||
* @throws IllegalArgumentException if the length of the specified
|
||||
* ZIP file comment is greater than 0xFFFF bytes
|
||||
* Sets the ZIP file comment. If {@code comment} is an empty string or
|
||||
* {@code null} then the output will have no ZIP file comment.
|
||||
*
|
||||
* @param comment the comment string, or an empty string or null for no comment
|
||||
*
|
||||
* @throws IllegalArgumentException if the length of the specified ZIP file
|
||||
* comment is greater than 0xFFFF bytes or if the {@code comment}
|
||||
* contains characters that cannot be mapped by the {@code Charset}
|
||||
* used to encode entry names and comments
|
||||
*/
|
||||
public void setComment(String comment) {
|
||||
byte[] bytes = null;
|
||||
|
||||
@ -105,6 +105,9 @@ public class LocaleResources {
|
||||
// TimeZoneNamesBundle exemplar city prefix
|
||||
private static final String TZNB_EXCITY_PREFIX = "timezone.excity.";
|
||||
|
||||
// TimeZoneNamesBundle explicit metazone dst offset prefix
|
||||
private static final String TZNB_METAZONE_DSTOFFSET_PREFIX = "metazone.dstoffset.";
|
||||
|
||||
// null singleton cache value
|
||||
private static final Object NULLOBJECT = new Object();
|
||||
|
||||
@ -321,7 +324,8 @@ public class LocaleResources {
|
||||
|
||||
if (Objects.isNull(data) || Objects.isNull(val = data.get())) {
|
||||
TimeZoneNamesBundle tznb = localeData.getTimeZoneNames(locale);
|
||||
if (key.startsWith(TZNB_EXCITY_PREFIX)) {
|
||||
if (key.startsWith(TZNB_EXCITY_PREFIX) ||
|
||||
key.startsWith(TZNB_METAZONE_DSTOFFSET_PREFIX)) {
|
||||
if (tznb.containsKey(key)) {
|
||||
val = tznb.getString(key);
|
||||
assert val instanceof String;
|
||||
@ -378,7 +382,8 @@ public class LocaleResources {
|
||||
Set<String[]> value = new LinkedHashSet<>();
|
||||
Set<String> tzIds = new HashSet<>(Arrays.asList(TimeZone.getAvailableIDs()));
|
||||
for (String key : keyset) {
|
||||
if (!key.startsWith(TZNB_EXCITY_PREFIX)) {
|
||||
if (!key.startsWith(TZNB_EXCITY_PREFIX) &&
|
||||
!key.startsWith(TZNB_METAZONE_DSTOFFSET_PREFIX)) {
|
||||
value.add(rb.getStringArray(key));
|
||||
tzIds.remove(key);
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.spi.TimeZoneNameProvider;
|
||||
import sun.util.calendar.ZoneInfo;
|
||||
import sun.util.cldr.CLDRLocaleProviderAdapter;
|
||||
import static sun.util.locale.provider.LocaleProviderAdapter.Type;
|
||||
import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR;
|
||||
|
||||
/**
|
||||
* Utility class that deals with the localized time zone names
|
||||
@ -169,10 +169,22 @@ public final class TimeZoneNameUtility {
|
||||
* Returns the canonical ID for the given ID
|
||||
*/
|
||||
public static Optional<String> canonicalTZID(String id) {
|
||||
return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(Type.CLDR))
|
||||
return ((CLDRLocaleProviderAdapter)LocaleProviderAdapter.forType(CLDR))
|
||||
.canonicalTZID(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@return the explicit metazone DST offset for the specified time zone ID, if exists}
|
||||
* @param tzid the time zone ID
|
||||
*/
|
||||
public static String explicitDstOffset(String tzid) {
|
||||
return (String) (LocaleProviderAdapter.forType(CLDR) instanceof CLDRLocaleProviderAdapter ca ?
|
||||
ca.getLocaleResources(Locale.ROOT)
|
||||
.getTimeZoneNames("metazone.dstoffset." +
|
||||
ca.canonicalTZID(tzid).orElse(tzid)) :
|
||||
null);
|
||||
}
|
||||
|
||||
private static String[] retrieveDisplayNamesImpl(String id, Locale locale) {
|
||||
LocaleServiceProviderPool pool =
|
||||
LocaleServiceProviderPool.getPool(TimeZoneNameProvider.class);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -43,8 +43,6 @@ package sun.util.resources;
|
||||
import java.util.Map;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
||||
@ -31,73 +31,54 @@
|
||||
#define CHECK_EXCEPTION if (env->ExceptionCheck()) { return; }
|
||||
|
||||
static jfieldID p_dwarf_context_ID = 0;
|
||||
static jint sa_RAX = -1;
|
||||
static jint sa_RDX = -1;
|
||||
static jint sa_RCX = -1;
|
||||
static jint sa_RBX = -1;
|
||||
static jint sa_RSI = -1;
|
||||
static jint sa_RDI = -1;
|
||||
static jint sa_RBP = -1;
|
||||
static jint sa_RSP = -1;
|
||||
static jint sa_R8 = -1;
|
||||
static jint sa_R9 = -1;
|
||||
static jint sa_R10 = -1;
|
||||
static jint sa_R11 = -1;
|
||||
static jint sa_R12 = -1;
|
||||
static jint sa_R13 = -1;
|
||||
static jint sa_R14 = -1;
|
||||
static jint sa_R15 = -1;
|
||||
|
||||
// DWARF_REG macro is used by DWARF_REGLIST.
|
||||
#define DWARF_REG(reg, _) \
|
||||
static jint sa_##reg = -1;
|
||||
|
||||
DWARF_REGLIST
|
||||
|
||||
#undef DWARF_REG
|
||||
|
||||
static jlong get_dwarf_context(JNIEnv *env, jobject obj) {
|
||||
return env->GetLongField(obj, p_dwarf_context_ID);
|
||||
}
|
||||
|
||||
#define SET_REG(env, reg, reg_cls) \
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: init0
|
||||
* Signature: ()V
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_init0
|
||||
(JNIEnv *env, jclass this_cls) {
|
||||
jclass cls = env->FindClass("sun/jvm/hotspot/debugger/linux/DwarfParser");
|
||||
CHECK_EXCEPTION
|
||||
p_dwarf_context_ID = env->GetFieldID(cls, "p_dwarf_context", "J");
|
||||
CHECK_EXCEPTION
|
||||
|
||||
jclass reg_cls = env->FindClass(THREAD_CONTEXT_CLASS);
|
||||
CHECK_EXCEPTION
|
||||
|
||||
// DWARF_REG macro is used by DWARF_REGLIST.
|
||||
#define DWARF_REG(reg, _) \
|
||||
jfieldID reg##_ID = env->GetStaticFieldID(reg_cls, #reg, "I"); \
|
||||
CHECK_EXCEPTION \
|
||||
sa_##reg = env->GetStaticIntField(reg_cls, reg##_ID); \
|
||||
CHECK_EXCEPTION
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
|
||||
* Method: init0
|
||||
* Signature: ()V
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_init0
|
||||
(JNIEnv *env, jclass this_cls) {
|
||||
jclass cls = env->FindClass("sun/jvm/hotspot/debugger/linux/amd64/DwarfParser");
|
||||
CHECK_EXCEPTION
|
||||
p_dwarf_context_ID = env->GetFieldID(cls, "p_dwarf_context", "J");
|
||||
CHECK_EXCEPTION
|
||||
DWARF_REGLIST
|
||||
|
||||
jclass reg_cls = env->FindClass("sun/jvm/hotspot/debugger/amd64/AMD64ThreadContext");
|
||||
CHECK_EXCEPTION
|
||||
SET_REG(env, RAX, reg_cls);
|
||||
SET_REG(env, RDX, reg_cls);
|
||||
SET_REG(env, RCX, reg_cls);
|
||||
SET_REG(env, RBX, reg_cls);
|
||||
SET_REG(env, RSI, reg_cls);
|
||||
SET_REG(env, RDI, reg_cls);
|
||||
SET_REG(env, RBP, reg_cls);
|
||||
SET_REG(env, RSP, reg_cls);
|
||||
SET_REG(env, R8, reg_cls);
|
||||
SET_REG(env, R9, reg_cls);
|
||||
SET_REG(env, R10, reg_cls);
|
||||
SET_REG(env, R11, reg_cls);
|
||||
SET_REG(env, R12, reg_cls);
|
||||
SET_REG(env, R13, reg_cls);
|
||||
SET_REG(env, R14, reg_cls);
|
||||
SET_REG(env, R15, reg_cls);
|
||||
#undef DWARF_REG
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: createDwarfContext
|
||||
* Signature: (J)J
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_createDwarfContext
|
||||
JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_createDwarfContext
|
||||
(JNIEnv *env, jclass this_cls, jlong lib) {
|
||||
DwarfParser *parser = new DwarfParser(reinterpret_cast<lib_info *>(lib));
|
||||
if (!parser->is_parseable()) {
|
||||
@ -113,36 +94,36 @@ JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_cr
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: destroyDwarfContext
|
||||
* Signature: (J)V
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_destroyDwarfContext
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_destroyDwarfContext
|
||||
(JNIEnv *env, jclass this_cls, jlong context) {
|
||||
DwarfParser *parser = reinterpret_cast<DwarfParser *>(context);
|
||||
delete parser;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: isIn0
|
||||
* Signature: (J)Z
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_isIn0
|
||||
JNIEXPORT jboolean JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_isIn0
|
||||
(JNIEnv *env, jobject this_obj, jlong pc) {
|
||||
DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
|
||||
return static_cast<jboolean>(parser->is_in(pc));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: processDwarf0
|
||||
* Signature: (J)V
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_processDwarf0
|
||||
JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_processDwarf0
|
||||
(JNIEnv *env, jobject this_obj, jlong pc) {
|
||||
DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
|
||||
if (!parser->process_dwarf(pc)) {
|
||||
@ -155,67 +136,106 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_pro
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: getCFARegister
|
||||
* Signature: ()I
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getCFARegister
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getCFARegister
|
||||
(JNIEnv *env, jobject this_obj) {
|
||||
DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
|
||||
|
||||
switch (parser->get_cfa_register()) {
|
||||
case RAX: return sa_RAX;
|
||||
case RDX: return sa_RDX;
|
||||
case RCX: return sa_RCX;
|
||||
case RBX: return sa_RBX;
|
||||
case RSI: return sa_RSI;
|
||||
case RDI: return sa_RDI;
|
||||
case RBP: return sa_RBP;
|
||||
case RSP: return sa_RSP;
|
||||
case R8: return sa_R8;
|
||||
case R9: return sa_R9;
|
||||
case R10: return sa_R10;
|
||||
case R11: return sa_R11;
|
||||
case R12: return sa_R12;
|
||||
case R13: return sa_R13;
|
||||
case R14: return sa_R14;
|
||||
case R15: return sa_R15;
|
||||
// DWARF_REG macro is used by DWARF_REGLIST.
|
||||
#define DWARF_REG(reg, _) \
|
||||
case reg: return sa_##reg;
|
||||
|
||||
DWARF_REGLIST
|
||||
|
||||
#undef DWARF_REG
|
||||
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: getCFAOffset
|
||||
* Signature: ()I
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getCFAOffset
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getCFAOffset
|
||||
(JNIEnv *env, jobject this_obj) {
|
||||
DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
|
||||
return parser->get_cfa_offset();
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: getOffsetFromCFA
|
||||
* Signature: (I)I
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getOffsetFromCFA
|
||||
(JNIEnv *env, jobject this_obj, jint sareg) {
|
||||
DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
|
||||
|
||||
// DWARF_REG macro is used by DWARF_REGLIST.
|
||||
#define DWARF_REG(reg, dwreg) \
|
||||
if (sareg == sa_##reg) { \
|
||||
return parser->get_offset_from_cfa(static_cast<enum DWARF_Register>(dwreg)); \
|
||||
} else
|
||||
|
||||
DWARF_REGLIST
|
||||
|
||||
#undef DWARF_REG
|
||||
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: getRARegister
|
||||
* Signature: ()I
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getRARegister
|
||||
(JNIEnv *env, jobject this_obj) {
|
||||
DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
|
||||
|
||||
switch (parser->get_ra_register()) {
|
||||
// DWARF_REG macro is used by DWARF_REGLIST.
|
||||
#define DWARF_REG(reg, _) \
|
||||
case reg: return sa_##reg;
|
||||
|
||||
DWARF_REGLIST
|
||||
|
||||
#undef DWARF_REG
|
||||
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: getReturnAddressOffsetFromCFA
|
||||
* Signature: ()I
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getReturnAddressOffsetFromCFA
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getReturnAddressOffsetFromCFA
|
||||
(JNIEnv *env, jobject this_obj) {
|
||||
DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
|
||||
return parser->get_offset_from_cfa(RA);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_jvm_hotspot_debugger_linux_amd64_DwarfParser
|
||||
* Class: sun_jvm_hotspot_debugger_linux_DwarfParser
|
||||
* Method: getBasePointerOffsetFromCFA
|
||||
* Signature: ()I
|
||||
*/
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_amd64_DwarfParser_getBasePointerOffsetFromCFA
|
||||
JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_linux_DwarfParser_getBasePointerOffsetFromCFA
|
||||
(JNIEnv *env, jobject this_obj) {
|
||||
DwarfParser *parser = reinterpret_cast<DwarfParser *>(get_dwarf_context(env, this_obj));
|
||||
return parser->get_offset_from_cfa(RBP);
|
||||
return parser->get_offset_from_cfa(BP);
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2021, NTT DATA.
|
||||
* Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2026, NTT DATA.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -289,6 +289,13 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_at
|
||||
snprintf(msg, sizeof(msg), "Can't attach to the process: %s", err_buf);
|
||||
THROW_NEW_DEBUGGER_EXCEPTION(msg);
|
||||
}
|
||||
|
||||
#ifdef __aarch64__
|
||||
if (pac_enabled(ph)) {
|
||||
printf("WARNING: PAC is enabled. Stack traces might be incomplete.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
env->SetLongField(this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
|
||||
fillThreadsAndLoadObjects(env, this_obj, ph);
|
||||
}
|
||||
@ -313,6 +320,13 @@ JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_at
|
||||
if ( (ph = Pgrab_core(execName_cstr, coreName_cstr)) == NULL) {
|
||||
THROW_NEW_DEBUGGER_EXCEPTION("Can't attach to the core file. For more information, export LIBSAPROC_DEBUG=1 and try again.");
|
||||
}
|
||||
|
||||
#ifdef __aarch64__
|
||||
if (pac_enabled(ph)) {
|
||||
printf("WARNING: PAC is enabled. Stack traces might be incomplete.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
env->SetLongField(this_obj, p_ps_prochandle_ID, (jlong)(intptr_t)ph);
|
||||
fillThreadsAndLoadObjects(env, this_obj, ph);
|
||||
}
|
||||
|
||||
@ -217,6 +217,20 @@ void DwarfParser::parse_dwarf_instructions(uintptr_t begin, uintptr_t pc, const
|
||||
_state.offset_from_cfa[reg] = _initial_state.offset_from_cfa[reg];
|
||||
break;
|
||||
}
|
||||
#ifdef __aarch64__
|
||||
// SA hasn't yet supported Pointer Authetication Code (PAC), so following
|
||||
// instructions would be ignored with warning message.
|
||||
// https://github.com/ARM-software/abi-aa/blob/2025Q4/aadwarf64/aadwarf64.rst
|
||||
case 0x2d: // DW_CFA_AARCH64_negate_ra_state
|
||||
print_debug("DWARF: DW_CFA_AARCH64_negate_ra_state is unimplemented.\n", op);
|
||||
break;
|
||||
case 0x2c: // DW_CFA_AARCH64_negate_ra_state_with_pc
|
||||
print_debug("DWARF: DW_CFA_AARCH64_negate_ra_state_with_pc is unimplemented.\n", op);
|
||||
break;
|
||||
case 0x2b: // DW_CFA_AARCH64_set_ra_state
|
||||
print_debug("DWARF: DW_CFA_AARCH64_set_ra_state is unimplemented.\n", op);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
print_debug("DWARF: Unknown opcode: 0x%x\n", op);
|
||||
return;
|
||||
|
||||
@ -30,30 +30,21 @@
|
||||
|
||||
#include "libproc_impl.h"
|
||||
|
||||
/*
|
||||
* from System V Application Binary Interface
|
||||
* AMD64 Architecture Processor Supplement
|
||||
* Figure 3.38: DWARF Register Number Mapping
|
||||
* https://software.intel.com/sites/default/files/article/402129/mpx-linux64-abi.pdf
|
||||
*/
|
||||
#ifdef __x86_64__
|
||||
#include "dwarf_regs_amd64.h"
|
||||
#elif defined(__aarch64__)
|
||||
#include "dwarf_regs_aarch64.h"
|
||||
#endif
|
||||
|
||||
enum DWARF_Register {
|
||||
RAX,
|
||||
RDX,
|
||||
RCX,
|
||||
RBX,
|
||||
RSI,
|
||||
RDI,
|
||||
RBP,
|
||||
RSP,
|
||||
R8,
|
||||
R9,
|
||||
R10,
|
||||
R11,
|
||||
R12,
|
||||
R13,
|
||||
R14,
|
||||
R15,
|
||||
RA,
|
||||
// DWARF_REG macro is used by DWARF_REGLIST and DWARF_PSEUDO_REGLIST.
|
||||
#define DWARF_REG(reg, no) \
|
||||
reg = no,
|
||||
|
||||
DWARF_REGLIST
|
||||
DWARF_PSEUDO_REGLIST
|
||||
|
||||
#undef DWARF_REG
|
||||
MAX_VALUE
|
||||
};
|
||||
|
||||
@ -94,6 +85,7 @@ class DwarfParser {
|
||||
bool process_dwarf(const uintptr_t pc);
|
||||
enum DWARF_Register get_cfa_register() { return _state.cfa_reg; }
|
||||
int get_cfa_offset() { return _state.cfa_offset; }
|
||||
enum DWARF_Register get_ra_register() { return _state.return_address_reg; }
|
||||
int get_offset_from_cfa(enum DWARF_Register reg) { return _state.offset_from_cfa[reg]; }
|
||||
|
||||
bool is_in(long pc) {
|
||||
|
||||
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2026, NTT DATA.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DWARF_REGS_AARCH64_H
|
||||
#define DWARF_REGS_AARCH64_H
|
||||
|
||||
#define THREAD_CONTEXT_CLASS "sun/jvm/hotspot/debugger/aarch64/AARCH64ThreadContext"
|
||||
|
||||
/*
|
||||
* from DWARF for the Arm (R) 64-bit Architecture (AArch64)
|
||||
* https://github.com/ARM-software/abi-aa/blob/2025Q4/aadwarf64/aadwarf64.rst
|
||||
* 4.1 DWARF register names
|
||||
*/
|
||||
#define DWARF_REGLIST \
|
||||
DWARF_REG(R0, 0) \
|
||||
DWARF_REG(R1, 1) \
|
||||
DWARF_REG(R2, 2) \
|
||||
DWARF_REG(R3, 3) \
|
||||
DWARF_REG(R4, 4) \
|
||||
DWARF_REG(R5, 5) \
|
||||
DWARF_REG(R6, 6) \
|
||||
DWARF_REG(R7, 7) \
|
||||
DWARF_REG(R8, 8) \
|
||||
DWARF_REG(R9, 9) \
|
||||
DWARF_REG(R10, 10) \
|
||||
DWARF_REG(R11, 11) \
|
||||
DWARF_REG(R12, 12) \
|
||||
DWARF_REG(R13, 13) \
|
||||
DWARF_REG(R14, 14) \
|
||||
DWARF_REG(R15, 15) \
|
||||
DWARF_REG(R16, 16) \
|
||||
DWARF_REG(R17, 17) \
|
||||
DWARF_REG(R18, 18) \
|
||||
DWARF_REG(R19, 19) \
|
||||
DWARF_REG(R20, 20) \
|
||||
DWARF_REG(R21, 21) \
|
||||
DWARF_REG(R22, 22) \
|
||||
DWARF_REG(R23, 23) \
|
||||
DWARF_REG(R24, 24) \
|
||||
DWARF_REG(R25, 25) \
|
||||
DWARF_REG(R26, 26) \
|
||||
DWARF_REG(R27, 27) \
|
||||
DWARF_REG(R28, 28) \
|
||||
DWARF_REG(FP, 29) \
|
||||
DWARF_REG(LR, 30) \
|
||||
DWARF_REG(SP, 31) \
|
||||
DWARF_REG(PC, 32)
|
||||
|
||||
// RA_SIGN_STATE might be needed in future to handle PAC.
|
||||
#define DWARF_PSEUDO_REGLIST
|
||||
|
||||
/* Aliases */
|
||||
#define BP FP
|
||||
#define RA LR
|
||||
|
||||
#endif
|
||||
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2026, NTT DATA.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DWARF_REGS_AMD64_H
|
||||
#define DWARF_REGS_AMD64_H
|
||||
|
||||
#define THREAD_CONTEXT_CLASS "sun/jvm/hotspot/debugger/amd64/AMD64ThreadContext"
|
||||
|
||||
/*
|
||||
* from System V Application Binary Interface
|
||||
* AMD64 Architecture Processor Supplement
|
||||
* https://refspecs.linuxbase.org/elf/x86_64-abi-0.99.pdf
|
||||
* Figure 3.36: DWARF Register Number Mapping
|
||||
*/
|
||||
#define DWARF_REGLIST \
|
||||
DWARF_REG(RAX, 0) \
|
||||
DWARF_REG(RDX, 1) \
|
||||
DWARF_REG(RCX, 2) \
|
||||
DWARF_REG(RBX, 3) \
|
||||
DWARF_REG(RSI, 4) \
|
||||
DWARF_REG(RDI, 5) \
|
||||
DWARF_REG(RBP, 6) \
|
||||
DWARF_REG(RSP, 7) \
|
||||
DWARF_REG(R8, 8) \
|
||||
DWARF_REG(R9, 9) \
|
||||
DWARF_REG(R10, 10) \
|
||||
DWARF_REG(R11, 11) \
|
||||
DWARF_REG(R12, 12) \
|
||||
DWARF_REG(R13, 13) \
|
||||
DWARF_REG(R14, 14) \
|
||||
DWARF_REG(R15, 15)
|
||||
|
||||
#define DWARF_PSEUDO_REGLIST \
|
||||
DWARF_REG(RA, 16)
|
||||
|
||||
/* Aliases */
|
||||
#define BP RBP
|
||||
|
||||
#endif
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -119,6 +119,10 @@ struct ps_prochandle* get_proc_handle(JNIEnv* env, jobject this_obj);
|
||||
|
||||
void throw_new_debugger_exception(JNIEnv* env, const char* errMsg);
|
||||
|
||||
#ifdef __aarch64__
|
||||
bool pac_enabled(struct ps_prochandle* ph);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -478,6 +478,12 @@ struct lib_info *find_lib_by_address(struct ps_prochandle* ph, uintptr_t pc) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __aarch64__
|
||||
bool pac_enabled(struct ps_prochandle* ph) {
|
||||
return ph->pac_enabled;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// proc service functions
|
||||
|
||||
|
||||
@ -115,6 +115,10 @@ struct ps_prochandle {
|
||||
int num_threads;
|
||||
thread_info* threads; // head of thread list
|
||||
struct core_data* core; // data only used for core dumps, NULL for process
|
||||
#ifdef __aarch64__
|
||||
// true if the HWCAP_PACA variant of Pointer Authentication Code (PAC) is enabled.
|
||||
bool pac_enabled;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -39,6 +39,12 @@
|
||||
#include "proc_service.h"
|
||||
#include "salibelf.h"
|
||||
|
||||
// HWCAP_PACA was introduced in glibc 2.30
|
||||
// https://sourceware.org/git/?p=glibc.git;a=commit;h=a2e57f89a35e6056c9488428e68c4889e114ef71
|
||||
#if defined(__aarch64__) && !defined(HWCAP_PACA)
|
||||
#define HWCAP_PACA (1 << 30)
|
||||
#endif
|
||||
|
||||
// This file has the libproc implementation to read core files.
|
||||
// For live processes, refer to ps_proc.c. Portions of this is adapted
|
||||
// /modelled after Solaris libproc.so (in particular Pcore.c)
|
||||
@ -290,6 +296,10 @@ static bool core_handle_note(struct ps_prochandle* ph, ELF_PHDR* note_phdr) {
|
||||
break;
|
||||
} else if (auxv->a_type == AT_SYSINFO_EHDR) {
|
||||
ph->core->vdso_addr = auxv->a_un.a_val;
|
||||
#ifdef __aarch64__
|
||||
} else if (auxv->a_type == AT_HWCAP) {
|
||||
ph->pac_enabled = auxv->a_un.a_val & HWCAP_PACA;
|
||||
#endif
|
||||
}
|
||||
auxv++;
|
||||
}
|
||||
@ -610,23 +620,38 @@ static uintptr_t calc_prelinked_load_address(struct ps_prochandle* ph, int lib_f
|
||||
return load_addr;
|
||||
}
|
||||
|
||||
static int handle_vdso_internal(struct ps_prochandle* ph, char* vdso_name, char* lib_name, size_t lib_name_len) {
|
||||
int lib_fd;
|
||||
struct utsname uts;
|
||||
uname(&uts);
|
||||
|
||||
char *vdso_path = (char*)malloc(lib_name_len);
|
||||
snprintf(vdso_path, lib_name_len, "/lib/modules/%s/vdso/%s", uts.release, vdso_name);
|
||||
print_debug("Try to open vDSO: %s\n", vdso_path);
|
||||
lib_fd = pathmap_open(vdso_path);
|
||||
if (lib_fd != -1) {
|
||||
print_debug("replace vDSO: %s -> %s\n", lib_name, vdso_path);
|
||||
strncpy(lib_name, vdso_path, lib_name_len);
|
||||
}
|
||||
|
||||
free(vdso_path);
|
||||
return lib_fd;
|
||||
}
|
||||
|
||||
// Check for vDSO binary in kernel directory (/lib/modules/<version>/vdso),
|
||||
// rewrite the given lib_name string if found.
|
||||
// Otherwise copy vDSO memory in coredump to temporal file generated by tmpfile().
|
||||
// Returns FD for vDSO (should be closed by caller), or -1 on error.
|
||||
static int handle_vdso(struct ps_prochandle* ph, char* lib_name, size_t lib_name_len) {
|
||||
int lib_fd;
|
||||
struct utsname uts;
|
||||
uname(&uts);
|
||||
|
||||
// Check vDSO binary first (for referring debuginfo if possible).
|
||||
char *vdso_path = (char*)malloc(lib_name_len);
|
||||
snprintf(vdso_path, lib_name_len, "/lib/modules/%s/vdso/vdso64.so", uts.release);
|
||||
lib_fd = pathmap_open(vdso_path);
|
||||
if (lib_fd != -1) {
|
||||
print_debug("replace vDSO: %s -> %s\n", lib_name, vdso_path);
|
||||
strncpy(lib_name, vdso_path, lib_name_len);
|
||||
} else {
|
||||
lib_fd = handle_vdso_internal(ph, "vdso64.so", lib_name, lib_name_len);
|
||||
if (lib_fd == -1) {
|
||||
// Try again with vdso.so
|
||||
lib_fd = handle_vdso_internal(ph, "vdso.so", lib_name, lib_name_len);
|
||||
}
|
||||
if (lib_fd == -1) {
|
||||
// Copy vDSO memory segment from core to temporal memory
|
||||
// if vDSO binary is not available.
|
||||
FILE* tmpf = tmpfile();
|
||||
@ -644,7 +669,6 @@ static int handle_vdso(struct ps_prochandle* ph, char* lib_name, size_t lib_name
|
||||
}
|
||||
}
|
||||
|
||||
free(vdso_path);
|
||||
return lib_fd;
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -36,6 +36,17 @@
|
||||
#include <sys/uio.h>
|
||||
#include "libproc_impl.h"
|
||||
|
||||
#ifdef __aarch64__
|
||||
#include <sys/auxv.h>
|
||||
|
||||
// HWCAP_PACA was introduced in glibc 2.30
|
||||
// https://sourceware.org/git/?p=glibc.git;a=commit;h=a2e57f89a35e6056c9488428e68c4889e114ef71
|
||||
#ifndef HWCAP_PACA
|
||||
#define HWCAP_PACA (1 << 30)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(x86_64) && !defined(amd64)
|
||||
#define amd64 1
|
||||
#endif
|
||||
@ -460,6 +471,10 @@ Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef __aarch64__
|
||||
ph->pac_enabled = HWCAP_PACA & getauxval(AT_HWCAP);
|
||||
#endif
|
||||
|
||||
// initialize ps_prochandle
|
||||
ph->pid = pid;
|
||||
if (add_thread_info(ph, ph->pid) == NULL) {
|
||||
|
||||
@ -417,10 +417,14 @@ static struct symtab* build_symtab_internal(int fd, const char *filename, bool t
|
||||
uintptr_t sym_value;
|
||||
char *sym_name = symtab->strs + syms->st_name;
|
||||
|
||||
// skip non-object and non-function symbols
|
||||
// skip non-object and non-function symbols, but STT_NOTYPE is allowed for
|
||||
// signal trampoline.
|
||||
int st_type = ELF_ST_TYPE(syms->st_info);
|
||||
if ( st_type != STT_FUNC && st_type != STT_OBJECT)
|
||||
if (st_type != STT_FUNC &&
|
||||
st_type != STT_OBJECT &&
|
||||
st_type != STT_NOTYPE) {
|
||||
continue;
|
||||
}
|
||||
// skip empty strings and undefined symbols
|
||||
if (*sym_name == '\0' || syms->st_shndx == SHN_UNDEF) continue;
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -39,7 +39,7 @@ public interface CFrame {
|
||||
public CFrame sender(ThreadProxy th);
|
||||
|
||||
/** Find sender frame with given FP and PC */
|
||||
public default CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) {
|
||||
public default CFrame sender(ThreadProxy th, Address senderSP, Address senderFP, Address senderPC) {
|
||||
return sender(th);
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2026, NTT DATA.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.debugger.linux;
|
||||
|
||||
import sun.jvm.hotspot.debugger.Address;
|
||||
import sun.jvm.hotspot.debugger.ThreadProxy;
|
||||
import sun.jvm.hotspot.debugger.UnalignedAddressException;
|
||||
import sun.jvm.hotspot.debugger.UnmappedAddressException;
|
||||
import sun.jvm.hotspot.debugger.cdbg.CFrame;
|
||||
import sun.jvm.hotspot.debugger.cdbg.ClosestSymbol;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.BasicCFrame;
|
||||
import sun.jvm.hotspot.runtime.VM;
|
||||
|
||||
public class DwarfCFrame extends BasicCFrame {
|
||||
|
||||
private Address sp;
|
||||
private Address fp;
|
||||
private Address pc;
|
||||
private Address cfa;
|
||||
private LinuxDebugger linuxDbg;
|
||||
private DwarfParser dwarf;
|
||||
private boolean use1ByteBeforeToLookup;
|
||||
|
||||
/**
|
||||
* @return DwarfParser instance for the PC, null if native library relates to the pc not found.
|
||||
* @throws DebuggerException if DWARF processing is failed.
|
||||
* For example: pc is not covered in this DWARF, Common Information Entry (CIE) has
|
||||
* language personality routine and/or Language Data Area (LSDA).
|
||||
*/
|
||||
protected static DwarfParser createDwarfParser(LinuxDebugger linuxDbg, Address pc) {
|
||||
Address libptr = linuxDbg.findLibPtrByAddress(pc);
|
||||
if (libptr != null) {
|
||||
DwarfParser dwarf = new DwarfParser(libptr);
|
||||
dwarf.processDwarf(pc);
|
||||
return dwarf;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected DwarfCFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, DwarfParser dwarf) {
|
||||
this(linuxDbg, sp, fp, cfa, pc, dwarf, false);
|
||||
}
|
||||
|
||||
protected DwarfCFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, DwarfParser dwarf, boolean use1ByteBeforeToLookup) {
|
||||
super(linuxDbg.getCDebugger());
|
||||
this.sp = sp;
|
||||
this.fp = fp;
|
||||
this.cfa = cfa;
|
||||
this.pc = pc;
|
||||
this.linuxDbg = linuxDbg;
|
||||
this.dwarf = dwarf;
|
||||
this.use1ByteBeforeToLookup = use1ByteBeforeToLookup;
|
||||
}
|
||||
|
||||
public Address sp() {
|
||||
return sp;
|
||||
}
|
||||
|
||||
public Address fp() {
|
||||
return fp;
|
||||
}
|
||||
|
||||
public Address pc() {
|
||||
return pc;
|
||||
}
|
||||
|
||||
public LinuxDebugger linuxDbg() {
|
||||
return linuxDbg;
|
||||
}
|
||||
|
||||
public DwarfParser dwarf() {
|
||||
return dwarf;
|
||||
}
|
||||
|
||||
// override base class impl to avoid ELF parsing
|
||||
@Override
|
||||
public ClosestSymbol closestSymbolToPC() {
|
||||
Address symAddr = use1ByteBeforeToLookup ? pc.addOffsetTo(-1) : pc;
|
||||
var sym = linuxDbg.lookup(linuxDbg.getAddressValue(symAddr));
|
||||
|
||||
// Returns a special symbol if the address is signal trampoline,
|
||||
// otherwise returns closest symbol generated by LinuxDebugger.
|
||||
return linuxDbg.isSignalTrampoline(symAddr)
|
||||
? new ClosestSymbol(sym.getName() + " <signal trampoline>", 0)
|
||||
: sym;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address localVariableBase() {
|
||||
return (dwarf != null && dwarf.isBPOffsetAvailable())
|
||||
? cfa.addOffsetTo(dwarf.getBasePointerOffsetFromCFA())
|
||||
: fp;
|
||||
}
|
||||
|
||||
protected boolean isValidFrame(Address senderCFA, Address senderFP) {
|
||||
// Both CFA and FP must not be null.
|
||||
if (senderCFA == null && senderFP == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// FP must not be null if CFA is null - it happens between Java frame and Native frame.
|
||||
// We cannot validate FP value because it might be used as GPR. Thus returns true
|
||||
// if FP is not null.
|
||||
if (senderCFA == null && senderFP != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// senderCFA must be greater than current CFA.
|
||||
if (senderCFA != null && senderCFA.greaterThanOrEqual(cfa)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, the frame is not valid.
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Address getSenderPC(Address senderPC) {
|
||||
if (senderPC != null) {
|
||||
return senderPC;
|
||||
}
|
||||
|
||||
try {
|
||||
return dwarf == null
|
||||
? fp.getAddressAt(VM.getVM().getAddressSize()) // Current frame is Java
|
||||
: cfa.getAddressAt(dwarf.getReturnAddressOffsetFromCFA()); // current frame is Native
|
||||
} catch (UnmappedAddressException | UnalignedAddressException _) {
|
||||
// Sender PC is invalid - maybe bottom of stack
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected Address getSenderSP(Address senderSP) {
|
||||
if (senderSP != null) {
|
||||
return senderSP;
|
||||
} else if (dwarf == null) {
|
||||
// Current frame is Java - skip saved BP and RA
|
||||
return fp.addOffsetTo(2 * VM.getVM().getAddressSize());
|
||||
} else {
|
||||
// Current frame is Native
|
||||
// CFA points SP at the call site in the previous frame.
|
||||
// See 6.4 Call Frame Information in DWARF Debugging Information Format
|
||||
// https://dwarfstd.org/dwarf4std.html
|
||||
return cfa;
|
||||
}
|
||||
}
|
||||
|
||||
protected Address getSenderFP(Address senderFP) {
|
||||
if (senderFP != null) {
|
||||
return senderFP;
|
||||
} else if (dwarf == null) { // Current frame is Java
|
||||
return fp.getAddressAt(0);
|
||||
} else { // Current frame is Native
|
||||
return dwarf.isBPOffsetAvailable()
|
||||
? cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA())
|
||||
: fp;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy th) {
|
||||
return sender(th, null, null, null);
|
||||
}
|
||||
|
||||
}
|
||||
@ -23,7 +23,7 @@
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.debugger.linux.amd64;
|
||||
package sun.jvm.hotspot.debugger.linux;
|
||||
|
||||
import java.lang.ref.Cleaner;
|
||||
import sun.jvm.hotspot.debugger.Address;
|
||||
@ -75,6 +75,8 @@ public class DwarfParser {
|
||||
|
||||
public native int getCFARegister();
|
||||
public native int getCFAOffset();
|
||||
public native int getOffsetFromCFA(int sareg);
|
||||
public native int getRARegister();
|
||||
public native int getReturnAddressOffsetFromCFA();
|
||||
public native int getBasePointerOffsetFromCFA();
|
||||
}
|
||||
@ -91,13 +91,7 @@ class LinuxCDebugger implements CDebugger {
|
||||
return new LinuxPPC64CFrame(dbg, sp, pc, LinuxDebuggerLocal.getAddressSize());
|
||||
} else if (cpu.equals("aarch64")) {
|
||||
AARCH64ThreadContext context = (AARCH64ThreadContext) thread.getContext();
|
||||
Address sp = context.getRegisterAsAddress(AARCH64ThreadContext.SP);
|
||||
if (sp == null) return null;
|
||||
Address fp = context.getRegisterAsAddress(AARCH64ThreadContext.FP);
|
||||
if (fp == null) return null;
|
||||
Address pc = context.getRegisterAsAddress(AARCH64ThreadContext.PC);
|
||||
if (pc == null) return null;
|
||||
return new LinuxAARCH64CFrame(dbg, sp, fp, pc);
|
||||
return LinuxAARCH64CFrame.getTopFrame(dbg, context);
|
||||
} else if (cpu.equals("riscv64")) {
|
||||
RISCV64ThreadContext context = (RISCV64ThreadContext) thread.getContext();
|
||||
Address sp = context.getRegisterAsAddress(RISCV64ThreadContext.SP);
|
||||
|
||||
@ -33,12 +33,17 @@ import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
by the architecture-specific subpackages. */
|
||||
|
||||
public interface LinuxDebugger extends JVMDebugger {
|
||||
// SIGHANDLER_NAMES holds the name of signal handler.
|
||||
public static final List<String> SIGHANDLER_NAMES = List.of(
|
||||
// SIGTRAMP_NAMES holds the name of signal trampoline.
|
||||
public static final List<String> SIGTRAMP_NAMES = List.of(
|
||||
// For AMD64
|
||||
// - sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c in glibc
|
||||
// - gdb/amd64-linux-tdep.c in GDB
|
||||
"__restore_rt"
|
||||
"__restore_rt",
|
||||
|
||||
// For AArch64
|
||||
// - arch/arm64/kernel/vdso/vdso.lds.S in Linux kernel
|
||||
"__kernel_rt_sigreturn",
|
||||
"VDSO_sigtramp"
|
||||
);
|
||||
|
||||
public String addressValueToString(long address) throws DebuggerException;
|
||||
|
||||
@ -133,7 +133,7 @@ public class LinuxDebuggerLocal extends DebuggerBase implements LinuxDebugger {
|
||||
@Override
|
||||
public boolean isSignalTrampoline(Address pc) {
|
||||
var sym = lookup(getAddressValue(pc));
|
||||
return sym == null ? false : SIGHANDLER_NAMES.contains(sym.getName());
|
||||
return sym == null ? false : SIGTRAMP_NAMES.contains(sym.getName());
|
||||
}
|
||||
|
||||
// Note on Linux threads are really processes. When target process is
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, Red Hat Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -25,73 +25,109 @@
|
||||
|
||||
package sun.jvm.hotspot.debugger.linux.aarch64;
|
||||
|
||||
import java.util.function.Function;
|
||||
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.aarch64.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
import sun.jvm.hotspot.code.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.runtime.aarch64.*;
|
||||
|
||||
public final class LinuxAARCH64CFrame extends BasicCFrame {
|
||||
public LinuxAARCH64CFrame(LinuxDebugger dbg, Address sp, Address fp, Address pc) {
|
||||
super(dbg.getCDebugger());
|
||||
this.sp = sp;
|
||||
this.fp = fp;
|
||||
this.pc = pc;
|
||||
this.dbg = dbg;
|
||||
public final class LinuxAARCH64CFrame extends DwarfCFrame {
|
||||
|
||||
private Address lr;
|
||||
|
||||
private static LinuxAARCH64CFrame getFrameFromReg(LinuxDebugger linuxDbg, Function<Integer, Address> getreg) {
|
||||
Address pc = getreg.apply(AARCH64ThreadContext.PC);
|
||||
Address sp = getreg.apply(AARCH64ThreadContext.SP);
|
||||
Address fp = getreg.apply(AARCH64ThreadContext.FP);
|
||||
Address lr = getreg.apply(AARCH64ThreadContext.LR);
|
||||
Address cfa = null;
|
||||
DwarfParser dwarf = createDwarfParser(linuxDbg, pc);
|
||||
|
||||
if (dwarf != null) { // Native frame
|
||||
cfa = getreg.apply(dwarf.getCFARegister())
|
||||
.addOffsetTo(dwarf.getCFAOffset());
|
||||
}
|
||||
|
||||
return (fp == null && cfa == null)
|
||||
? null
|
||||
: new LinuxAARCH64CFrame(linuxDbg, sp, fp, cfa, pc, lr, dwarf);
|
||||
}
|
||||
|
||||
// override base class impl to avoid ELF parsing
|
||||
public ClosestSymbol closestSymbolToPC() {
|
||||
// try native lookup in debugger.
|
||||
return dbg.lookup(dbg.getAddressValue(pc()));
|
||||
public static LinuxAARCH64CFrame getTopFrame(LinuxDebugger linuxDbg, ThreadContext context) {
|
||||
return getFrameFromReg(linuxDbg, context::getRegisterAsAddress);
|
||||
}
|
||||
|
||||
public Address pc() {
|
||||
return pc;
|
||||
private LinuxAARCH64CFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, Address lr, DwarfParser dwarf) {
|
||||
this(linuxDbg, sp, fp, cfa, pc, lr, dwarf, false);
|
||||
}
|
||||
|
||||
public Address localVariableBase() {
|
||||
return fp;
|
||||
private LinuxAARCH64CFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, DwarfParser dwarf) {
|
||||
this(linuxDbg, sp, fp, cfa, pc, null, dwarf, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy thread) {
|
||||
return sender(thread, null, null, null);
|
||||
private LinuxAARCH64CFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, DwarfParser dwarf, boolean use1ByteBeforeToLookup) {
|
||||
this(linuxDbg, sp, fp, cfa, pc, null, dwarf, use1ByteBeforeToLookup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy thread, Address nextSP, Address nextFP, Address nextPC) {
|
||||
// Check fp
|
||||
// Skip if both nextFP and nextPC are given - do not need to load from fp.
|
||||
if (nextFP == null && nextPC == null) {
|
||||
if (fp == null) {
|
||||
return null;
|
||||
private LinuxAARCH64CFrame(LinuxDebugger linuxDbg, Address sp, Address fp, Address cfa, Address pc, Address lr, DwarfParser dwarf, boolean use1ByteBeforeToLookup) {
|
||||
super(linuxDbg, sp, fp, cfa, pc, dwarf, use1ByteBeforeToLookup);
|
||||
|
||||
if (dwarf != null) {
|
||||
// Prioritize to use RA from DWARF instead of LR
|
||||
var senderPCFromDwarf = getSenderPC(null);
|
||||
if (senderPCFromDwarf != null) {
|
||||
lr = senderPCFromDwarf;
|
||||
} else if (lr != null) {
|
||||
// We should set passed lr to LR of this frame,
|
||||
// but throws DebuggerException if lr is not used for RA.
|
||||
var raReg = dwarf.getRARegister();
|
||||
if (raReg != AARCH64ThreadContext.LR) {
|
||||
throw new DebuggerException("Unexpected RA register: " + raReg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check alignment of fp
|
||||
if (dbg.getAddressValue(fp) % (2 * ADDRESS_SIZE) != 0) {
|
||||
this.lr = lr;
|
||||
}
|
||||
|
||||
private Address getSenderCFA(DwarfParser senderDwarf, Address senderSP, Address senderFP) {
|
||||
if (senderDwarf == null) { // Sender frame is Java
|
||||
// CFA is not available on Java frame
|
||||
return null;
|
||||
}
|
||||
|
||||
// Sender frame is Native
|
||||
int senderCFAReg = senderDwarf.getCFARegister();
|
||||
return switch(senderCFAReg){
|
||||
case AARCH64ThreadContext.FP -> senderFP.addOffsetTo(senderDwarf.getCFAOffset());
|
||||
case AARCH64ThreadContext.SP -> senderSP.addOffsetTo(senderDwarf.getCFAOffset());
|
||||
default -> throw new DebuggerException("Unsupported CFA register: " + senderCFAReg);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy thread, Address senderSP, Address senderFP, Address senderPC) {
|
||||
if (linuxDbg().isSignalTrampoline(pc())) {
|
||||
// SP points signal context
|
||||
// https://github.com/torvalds/linux/blob/v6.17/arch/arm64/kernel/signal.c#L1357
|
||||
return getFrameFromReg(linuxDbg(), r -> LinuxAARCH64ThreadContext.getRegFromSignalTrampoline(sp(), r.intValue()));
|
||||
}
|
||||
|
||||
if (senderPC == null) {
|
||||
// Use getSenderPC() if current frame is Java because we cannot rely on lr in this case.
|
||||
senderPC = dwarf() == null ? getSenderPC(null) : lr;
|
||||
if (senderPC == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextFP == null) {
|
||||
nextFP = fp.getAddressAt(0 * ADDRESS_SIZE);
|
||||
}
|
||||
if (nextFP == null) {
|
||||
return null;
|
||||
}
|
||||
senderFP = getSenderFP(senderFP);
|
||||
|
||||
if (nextPC == null) {
|
||||
nextPC = fp.getAddressAt(1 * ADDRESS_SIZE);
|
||||
}
|
||||
if (nextPC == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (nextSP == null) {
|
||||
if (senderSP == null) {
|
||||
CodeCache cc = VM.getVM().getCodeCache();
|
||||
CodeBlob currentBlob = cc.findBlobUnsafe(pc());
|
||||
|
||||
@ -99,29 +135,62 @@ public final class LinuxAARCH64CFrame extends BasicCFrame {
|
||||
if (currentBlob != null && (currentBlob.isContinuationStub() || currentBlob.isNativeMethod())) {
|
||||
// Use FP since it should always be valid for these cases.
|
||||
// TODO: These should be walked as Frames not CFrames.
|
||||
nextSP = fp.addOffsetTo(2 * ADDRESS_SIZE);
|
||||
senderSP = fp().addOffsetTo(2 * VM.getVM().getAddressSize());
|
||||
} else {
|
||||
CodeBlob codeBlob = cc.findBlobUnsafe(nextPC);
|
||||
CodeBlob codeBlob = cc.findBlobUnsafe(senderPC);
|
||||
boolean useCodeBlob = codeBlob != null && codeBlob.getFrameSize() > 0;
|
||||
nextSP = useCodeBlob ? nextFP.addOffsetTo((2 * ADDRESS_SIZE) - codeBlob.getFrameSize()) : nextFP;
|
||||
senderSP = useCodeBlob ? senderFP.addOffsetTo((2 * VM.getVM().getAddressSize()) - codeBlob.getFrameSize()) : getSenderSP(null);
|
||||
}
|
||||
}
|
||||
if (nextSP == null) {
|
||||
if (senderSP == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new LinuxAARCH64CFrame(dbg, nextSP, nextFP, nextPC);
|
||||
DwarfParser senderDwarf = null;
|
||||
boolean fallback = false;
|
||||
try {
|
||||
senderDwarf = createDwarfParser(linuxDbg(), senderPC);
|
||||
} catch (DebuggerException _) {
|
||||
// Try again with PC-1 in case PC is just outside function bounds,
|
||||
// due to function ending with a `call` instruction.
|
||||
try {
|
||||
senderDwarf = createDwarfParser(linuxDbg(), senderPC.addOffsetTo(-1));
|
||||
fallback = true;
|
||||
} catch (DebuggerException _) {
|
||||
if (linuxDbg().isSignalTrampoline(senderPC)) {
|
||||
// We can use the caller frame if it is a signal trampoline.
|
||||
// DWARF processing might fail because vdso.so .eh_frame is not required on aarch64.
|
||||
return new LinuxAARCH64CFrame(linuxDbg(), senderSP, senderFP, null, senderPC, senderDwarf);
|
||||
}
|
||||
|
||||
// DWARF processing should succeed when the frame is native
|
||||
// but it might fail if Common Information Entry (CIE) has language
|
||||
// personality routine and/or Language Specific Data Area (LSDA).
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Address senderCFA = getSenderCFA(senderDwarf, senderSP, senderFP);
|
||||
return isValidFrame(senderCFA, senderFP)
|
||||
? new LinuxAARCH64CFrame(linuxDbg(), senderSP, senderFP, senderCFA, senderPC, senderDwarf, fallback)
|
||||
: null;
|
||||
} catch (DebuggerException e) {
|
||||
if (linuxDbg().isSignalTrampoline(senderPC)) {
|
||||
// We can use the caller frame if it is a signal trampoline.
|
||||
// getSenderCFA() might fail because DwarfParser cannot find out CFA register.
|
||||
return new LinuxAARCH64CFrame(linuxDbg(), senderSP, senderFP, null, senderPC, senderDwarf, fallback);
|
||||
}
|
||||
|
||||
// Rethrow the original exception if getSenderCFA() failed
|
||||
// and the caller is not signal trampoline.
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame toFrame() {
|
||||
return new AARCH64Frame(sp, fp, pc);
|
||||
return new AARCH64Frame(sp(), fp(), pc());
|
||||
}
|
||||
|
||||
// package/class internals only
|
||||
private static final int ADDRESS_SIZE = 8;
|
||||
private Address pc;
|
||||
private Address sp;
|
||||
private Address fp;
|
||||
private LinuxDebugger dbg;
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, Red Hat Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
@ -28,6 +28,7 @@ package sun.jvm.hotspot.debugger.linux.aarch64;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.aarch64.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
|
||||
public class LinuxAARCH64ThreadContext extends AARCH64ThreadContext {
|
||||
private LinuxDebugger debugger;
|
||||
@ -44,4 +45,24 @@ public class LinuxAARCH64ThreadContext extends AARCH64ThreadContext {
|
||||
public Address getRegisterAsAddress(int index) {
|
||||
return debugger.newAddress(getRegister(index));
|
||||
}
|
||||
|
||||
public static Address getRegFromSignalTrampoline(Address sp, int index) {
|
||||
// ucontext_t locates at 2nd element of rt_sigframe.
|
||||
// See definition of rt_sigframe in arch/arm/kernel/signal.h
|
||||
// in Linux Kernel.
|
||||
Address addrUContext = sp.addOffsetTo(128); // sizeof(siginfo_t) = 128
|
||||
Address addrUCMContext = addrUContext.addOffsetTo(176); // offsetof(ucontext_t, uc_mcontext) = 176
|
||||
|
||||
Address ptrCallerSP = addrUCMContext.addOffsetTo(256); // offsetof(uc_mcontext, sp) = 256
|
||||
Address ptrCallerPC = addrUCMContext.addOffsetTo(264); // offsetof(uc_mcontext, pc) = 264
|
||||
Address ptrCallerRegs = addrUCMContext.addOffsetTo(8); // offsetof(uc_mcontext, regs) = 8
|
||||
|
||||
return switch(index) {
|
||||
case AARCH64ThreadContext.FP -> ptrCallerRegs.getAddressAt(AARCH64ThreadContext.FP * VM.getVM().getAddressSize());
|
||||
case AARCH64ThreadContext.LR -> ptrCallerRegs.getAddressAt(AARCH64ThreadContext.LR * VM.getVM().getAddressSize());
|
||||
case AARCH64ThreadContext.SP -> ptrCallerSP.getAddressAt(0);
|
||||
case AARCH64ThreadContext.PC -> ptrCallerPC.getAddressAt(0);
|
||||
default -> throw new IllegalArgumentException("Unsupported register index: " + index);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,181 +29,82 @@ import java.util.function.Function;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.debugger.amd64.*;
|
||||
import sun.jvm.hotspot.debugger.linux.*;
|
||||
import sun.jvm.hotspot.debugger.linux.amd64.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.*;
|
||||
import sun.jvm.hotspot.debugger.cdbg.basic.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.runtime.amd64.*;
|
||||
|
||||
public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
public final class LinuxAMD64CFrame extends DwarfCFrame {
|
||||
|
||||
private static LinuxAMD64CFrame getFrameFromReg(LinuxDebugger dbg, Function<Integer, Address> getreg) {
|
||||
private static LinuxAMD64CFrame getFrameFromReg(LinuxDebugger linuxDbg, Function<Integer, Address> getreg) {
|
||||
Address rip = getreg.apply(AMD64ThreadContext.RIP);
|
||||
Address rsp = getreg.apply(AMD64ThreadContext.RSP);
|
||||
Address rbp = getreg.apply(AMD64ThreadContext.RBP);
|
||||
Address libptr = dbg.findLibPtrByAddress(rip);
|
||||
Address cfa = null;
|
||||
DwarfParser dwarf = null;
|
||||
|
||||
if (libptr != null) { // Native frame
|
||||
dwarf = new DwarfParser(libptr);
|
||||
try {
|
||||
dwarf.processDwarf(rip);
|
||||
} catch (DebuggerException e) {
|
||||
// DWARF processing should succeed when the frame is native
|
||||
// but it might fail if Common Information Entry (CIE) has language
|
||||
// personality routine and/or Language Specific Data Area (LSDA).
|
||||
return new LinuxAMD64CFrame(dbg, rsp, rbp, cfa, rip, dwarf, true);
|
||||
}
|
||||
DwarfParser dwarf = createDwarfParser(linuxDbg, rip);
|
||||
|
||||
if (dwarf != null) { // Native frame
|
||||
cfa = getreg.apply(dwarf.getCFARegister())
|
||||
.addOffsetTo(dwarf.getCFAOffset());
|
||||
}
|
||||
|
||||
return (rbp == null && cfa == null)
|
||||
? null
|
||||
: new LinuxAMD64CFrame(dbg, rsp, rbp, cfa, rip, dwarf);
|
||||
: new LinuxAMD64CFrame(linuxDbg, rsp, rbp, cfa, rip, dwarf);
|
||||
}
|
||||
|
||||
public static LinuxAMD64CFrame getTopFrame(LinuxDebugger dbg, ThreadContext context) {
|
||||
return getFrameFromReg(dbg, context::getRegisterAsAddress);
|
||||
public static LinuxAMD64CFrame getTopFrame(LinuxDebugger linuxDbg, ThreadContext context) {
|
||||
return getFrameFromReg(linuxDbg, context::getRegisterAsAddress);
|
||||
}
|
||||
|
||||
private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address rbp, Address cfa, Address rip, DwarfParser dwarf) {
|
||||
this(dbg, rsp, rbp, cfa, rip, dwarf, false);
|
||||
private LinuxAMD64CFrame(LinuxDebugger linuxDbg, Address rsp, Address rbp, Address cfa, Address rip, DwarfParser dwarf) {
|
||||
this(linuxDbg, rsp, rbp, cfa, rip, dwarf, false);
|
||||
}
|
||||
|
||||
private LinuxAMD64CFrame(LinuxDebugger dbg, Address rsp, Address rbp, Address cfa, Address rip, DwarfParser dwarf, boolean use1ByteBeforeToLookup) {
|
||||
super(dbg.getCDebugger());
|
||||
this.rsp = rsp;
|
||||
this.rbp = rbp;
|
||||
this.cfa = cfa;
|
||||
this.rip = rip;
|
||||
this.dbg = dbg;
|
||||
this.dwarf = dwarf;
|
||||
this.use1ByteBeforeToLookup = use1ByteBeforeToLookup;
|
||||
private LinuxAMD64CFrame(LinuxDebugger linuxDbg, Address rsp, Address rbp, Address cfa, Address rip, DwarfParser dwarf, boolean use1ByteBeforeToLookup) {
|
||||
super(linuxDbg, rsp, rbp, cfa, rip, dwarf, use1ByteBeforeToLookup);
|
||||
}
|
||||
|
||||
// override base class impl to avoid ELF parsing
|
||||
public ClosestSymbol closestSymbolToPC() {
|
||||
Address symAddr = use1ByteBeforeToLookup ? pc().addOffsetTo(-1) : pc();
|
||||
var sym = dbg.lookup(dbg.getAddressValue(symAddr));
|
||||
|
||||
// Returns a special symbol if the address is signal handler,
|
||||
// otherwise returns closest symbol generated by LinuxDebugger.
|
||||
return dbg.isSignalTrampoline(symAddr)
|
||||
? new ClosestSymbol(sym.getName() + " <signal trampoline>", 0)
|
||||
: sym;
|
||||
}
|
||||
|
||||
public Address pc() {
|
||||
return rip;
|
||||
}
|
||||
|
||||
public Address localVariableBase() {
|
||||
return (dwarf != null && dwarf.isBPOffsetAvailable())
|
||||
? cfa.addOffsetTo(dwarf.getBasePointerOffsetFromCFA())
|
||||
: rbp;
|
||||
}
|
||||
|
||||
private Address getNextPC() {
|
||||
try {
|
||||
return dwarf == null
|
||||
? rbp.getAddressAt(ADDRESS_SIZE) // Java frame
|
||||
: cfa.getAddressAt(dwarf.getReturnAddressOffsetFromCFA()); // Native frame
|
||||
} catch (UnmappedAddressException | UnalignedAddressException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isValidFrame(Address nextCFA, Address nextRBP) {
|
||||
// Both CFA and RBP must not be null.
|
||||
if (nextCFA == null && nextRBP == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// RBP must not be null if CFA is null - it happens between Java frame and Native frame.
|
||||
// We cannot validate RBP value because it might be used as GPR. Thus returns true
|
||||
// if RBP is not null.
|
||||
if (nextCFA == null && nextRBP != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// nextCFA must be greater than current CFA.
|
||||
if (nextCFA != null && nextCFA.greaterThanOrEqual(cfa)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, the frame is not valid.
|
||||
return false;
|
||||
}
|
||||
|
||||
private Address getNextRSP() {
|
||||
return dwarf == null ? rbp.addOffsetTo(2 * ADDRESS_SIZE) // Java frame - skip saved BP and RA
|
||||
: cfa.addOffsetTo(dwarf.getReturnAddressOffsetFromCFA())
|
||||
.addOffsetTo(ADDRESS_SIZE); // Native frame
|
||||
}
|
||||
|
||||
private Address getNextRBP(Address senderFP) {
|
||||
if (senderFP != null) {
|
||||
return senderFP;
|
||||
} else if (dwarf == null) { // Current frame is Java
|
||||
return rbp.getAddressAt(0);
|
||||
} else { // Current frame is Native
|
||||
return dwarf.isBPOffsetAvailable()
|
||||
? cfa.getAddressAt(dwarf.getBasePointerOffsetFromCFA())
|
||||
: rbp;
|
||||
}
|
||||
}
|
||||
|
||||
private Address getNextCFA(DwarfParser nextDwarf, Address senderFP, Address senderPC) {
|
||||
if (nextDwarf == null) { // Next frame is Java
|
||||
private Address getSenderCFA(DwarfParser senderDwarf, Address senderSP, Address senderFP) {
|
||||
if (senderDwarf == null) { // Sender frame is Java
|
||||
// CFA is not available on Java frame
|
||||
return null;
|
||||
}
|
||||
|
||||
// Next frame is Native
|
||||
int nextCFAReg = nextDwarf.getCFARegister();
|
||||
return switch(nextCFAReg){
|
||||
case AMD64ThreadContext.RBP -> getNextRBP(senderFP).addOffsetTo(nextDwarf.getCFAOffset());
|
||||
case AMD64ThreadContext.RSP -> getNextRSP().addOffsetTo(nextDwarf.getCFAOffset());
|
||||
default -> throw new DebuggerException("Unsupported CFA register: " + nextCFAReg);
|
||||
// Sender frame is Native
|
||||
int senderCFAReg = senderDwarf.getCFARegister();
|
||||
return switch(senderCFAReg){
|
||||
case AMD64ThreadContext.RBP -> senderFP.addOffsetTo(senderDwarf.getCFAOffset());
|
||||
case AMD64ThreadContext.RSP -> senderSP.addOffsetTo(senderDwarf.getCFAOffset());
|
||||
default -> throw new DebuggerException("Unsupported CFA register: " + senderCFAReg);
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy th) {
|
||||
return sender(th, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFrame sender(ThreadProxy th, Address sp, Address fp, Address pc) {
|
||||
if (dbg.isSignalTrampoline(pc())) {
|
||||
public CFrame sender(ThreadProxy th, Address senderSP, Address senderFP, Address senderPC) {
|
||||
if (linuxDbg().isSignalTrampoline(pc())) {
|
||||
// RSP points signal context
|
||||
// https://github.com/torvalds/linux/blob/v6.17/arch/x86/kernel/signal.c#L94
|
||||
return getFrameFromReg(dbg, r -> LinuxAMD64ThreadContext.getRegFromSignalTrampoline(this.rsp, r.intValue()));
|
||||
return getFrameFromReg(linuxDbg(), r -> LinuxAMD64ThreadContext.getRegFromSignalTrampoline(sp(), r.intValue()));
|
||||
}
|
||||
|
||||
ThreadContext context = th.getContext();
|
||||
|
||||
Address nextRSP = sp != null ? sp : getNextRSP();
|
||||
if (nextRSP == null) {
|
||||
senderSP = getSenderSP(senderSP);
|
||||
if (senderSP == null) {
|
||||
return null;
|
||||
}
|
||||
Address nextPC = pc != null ? pc : getNextPC();
|
||||
if (nextPC == null) {
|
||||
senderPC = getSenderPC(senderPC);
|
||||
if (senderPC == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
DwarfParser nextDwarf = null;
|
||||
DwarfParser senderDwarf = null;
|
||||
boolean fallback = false;
|
||||
try {
|
||||
nextDwarf = createDwarfParser(nextPC);
|
||||
senderDwarf = createDwarfParser(linuxDbg(), senderPC);
|
||||
} catch (DebuggerException _) {
|
||||
// Try again with RIP-1 in case RIP is just outside function bounds,
|
||||
// Try again with PC-1 in case PC is just outside function bounds,
|
||||
// due to function ending with a `call` instruction.
|
||||
try {
|
||||
nextDwarf = createDwarfParser(nextPC.addOffsetTo(-1));
|
||||
senderDwarf = createDwarfParser(linuxDbg(), senderPC.addOffsetTo(-1));
|
||||
fallback = true;
|
||||
} catch (DebuggerException _) {
|
||||
// DWARF processing should succeed when the frame is native
|
||||
@ -213,56 +114,29 @@ public final class LinuxAMD64CFrame extends BasicCFrame {
|
||||
}
|
||||
}
|
||||
|
||||
Address nextRBP = getNextRBP(fp);
|
||||
senderFP = getSenderFP(senderFP);
|
||||
|
||||
try {
|
||||
Address nextCFA = getNextCFA(nextDwarf, fp, nextPC);
|
||||
return isValidFrame(nextCFA, nextRBP)
|
||||
? new LinuxAMD64CFrame(dbg, nextRSP, nextRBP, nextCFA, nextPC, nextDwarf, fallback)
|
||||
Address senderCFA = getSenderCFA(senderDwarf, senderSP, senderFP);
|
||||
return isValidFrame(senderCFA, senderFP)
|
||||
? new LinuxAMD64CFrame(linuxDbg(), senderSP, senderFP, senderCFA, senderPC, senderDwarf, fallback)
|
||||
: null;
|
||||
} catch (DebuggerException e) {
|
||||
if (dbg.isSignalTrampoline(nextPC)) {
|
||||
// We can through the caller frame if it is signal trampoline.
|
||||
// getNextCFA() might fail because DwarfParser cannot find out CFA register.
|
||||
return new LinuxAMD64CFrame(dbg, nextRSP, nextRBP, null, nextPC, nextDwarf, fallback);
|
||||
if (linuxDbg().isSignalTrampoline(senderPC)) {
|
||||
// We can use the caller frame if it is a signal trampoline.
|
||||
// getSenderCFA() might fail because DwarfParser cannot find out CFA register.
|
||||
return new LinuxAMD64CFrame(linuxDbg(), senderSP, senderFP, null, senderPC, senderDwarf, fallback);
|
||||
}
|
||||
|
||||
// Rethrow the original exception if getNextCFA() failed
|
||||
// Rethrow the original exception if getSenderCFA() failed
|
||||
// and the caller is not signal trampoline.
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private DwarfParser createDwarfParser(Address pc) throws DebuggerException {
|
||||
DwarfParser nextDwarf = null;
|
||||
Address libptr = dbg.findLibPtrByAddress(pc);
|
||||
if (libptr != null) {
|
||||
try {
|
||||
nextDwarf = new DwarfParser(libptr);
|
||||
} catch (DebuggerException _) {
|
||||
// Bail out to Java frame
|
||||
}
|
||||
}
|
||||
|
||||
if (nextDwarf != null) {
|
||||
nextDwarf.processDwarf(pc);
|
||||
}
|
||||
|
||||
return nextDwarf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Frame toFrame() {
|
||||
return new AMD64Frame(rsp, localVariableBase(), rip);
|
||||
return new AMD64Frame(sp(), localVariableBase(), pc());
|
||||
}
|
||||
|
||||
// package/class internals only
|
||||
private static final int ADDRESS_SIZE = 8;
|
||||
private Address rsp;
|
||||
private Address rbp;
|
||||
private Address rip;
|
||||
private Address cfa;
|
||||
private LinuxDebugger dbg;
|
||||
private DwarfParser dwarf;
|
||||
private boolean use1ByteBeforeToLookup;
|
||||
}
|
||||
|
||||
@ -1246,7 +1246,11 @@ class ZipFileSystem extends FileSystem {
|
||||
private LinkedHashMap<IndexNode, IndexNode> inodes;
|
||||
|
||||
final byte[] getBytes(String name) {
|
||||
return zc.getBytes(name);
|
||||
try {
|
||||
return zc.getBytes(name);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new InvalidPathException(name, "unmappable character in path name");
|
||||
}
|
||||
}
|
||||
|
||||
final String getString(byte[] name) {
|
||||
|
||||
@ -58,6 +58,7 @@
|
||||
and that causes invalid macro expansion.
|
||||
*/
|
||||
#undef aarch64
|
||||
#undef arm
|
||||
#include <capstone.h>
|
||||
|
||||
#include "hsdis.h"
|
||||
@ -163,9 +164,9 @@ void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va,
|
||||
size_t count = cs_disasm(cs_handle, buffer, length, (uintptr_t) buffer, 0 , &insn);
|
||||
if (count) {
|
||||
for (unsigned int j = 0; j < count; j++) {
|
||||
(*event_callback)(event_stream, "insn", (void*) insn[j].address);
|
||||
(*event_callback)(event_stream, "insn", (void*)(uintptr_t) insn[j].address);
|
||||
print("%s\t\t%s", insn[j].mnemonic, insn[j].op_str);
|
||||
(*event_callback)(event_stream, "/insn", (void*) (insn[j].address + insn[j].size));
|
||||
(*event_callback)(event_stream, "/insn", (void*)(uintptr_t) (insn[j].address + insn[j].size));
|
||||
if (newline) {
|
||||
/* follow each complete insn by a nice newline */
|
||||
print("\n");
|
||||
|
||||
@ -56,7 +56,6 @@ compiler/c2/irTests/TestDuplicateBackedge.java 8318904 generic-all
|
||||
|
||||
compiler/codecache/jmx/PoolsIndependenceTest.java 8264632 macosx-all
|
||||
|
||||
compiler/vectorapi/reshape/TestVectorReinterpret.java 8348519 linux-s390x
|
||||
compiler/vectorapi/VectorRebracket128Test.java 8330538 generic-all
|
||||
|
||||
compiler/vectorization/TestVectorAlgorithms.java#noSuperWord 8376803 aix-ppc64,linux-s390x
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2026 IBM Corporation. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8380158
|
||||
* @summary C2: compiler/c2/TestGVNCrash.java asserts with adr and adr_type must agree
|
||||
* @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation
|
||||
* -XX:CompileOnly=compiler.arraycopy.TestACNonEscapingSrcBadAddPBaseType::test1
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:StressSeed=946074051 ${test.main.class}
|
||||
* @run main/othervm -XX:-TieredCompilation -XX:-UseOnStackReplacement -XX:-BackgroundCompilation
|
||||
* -XX:CompileOnly=compiler.arraycopy.TestACNonEscapingSrcBadAddPBaseType::test1
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN ${test.main.class}
|
||||
* @run main ${test.main.class}
|
||||
*/
|
||||
|
||||
package compiler.arraycopy;
|
||||
|
||||
public class TestACNonEscapingSrcBadAddPBaseType {
|
||||
private static volatile int volatileField;
|
||||
|
||||
public static void main(String[] args) {
|
||||
int[] dst = new int[2];
|
||||
for (int i = 0; i < 20_000; i++) {
|
||||
test1(dst);
|
||||
}
|
||||
}
|
||||
|
||||
private static void test1(int[] dst) {
|
||||
int[] array = new int[2];
|
||||
A a = new A(array);
|
||||
volatileField = 42;
|
||||
int[] src = a.src;
|
||||
System.arraycopy(src, 0, dst, 0, src.length);
|
||||
System.arraycopy(src, 0, dst, 0, src.length);
|
||||
}
|
||||
|
||||
private static class A {
|
||||
private final int[] src;
|
||||
|
||||
public A(int[] src) {
|
||||
this.src = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022 SAP SE. All rights reserved.ights reserved.
|
||||
* Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2022, 2025 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -28,6 +28,7 @@
|
||||
* @requires vm.compMode == "Xmixed"
|
||||
* @requires vm.opt.TieredCompilation == null | vm.opt.TieredCompilation == true
|
||||
* @requires vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary test allocation failure of method handle intrinsic in profiled/non-profiled space
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
@ -39,6 +40,11 @@
|
||||
* -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:ReservedCodeCacheSize=16m -XX:+SegmentedCodeCache
|
||||
* compiler.codecache.MHIntrinsicAllocFailureTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:ReservedCodeCacheSize=20m -XX:+SegmentedCodeCache
|
||||
* -XX:+TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=4M
|
||||
* compiler.codecache.MHIntrinsicAllocFailureTest
|
||||
*/
|
||||
|
||||
package compiler.codecache;
|
||||
@ -73,7 +79,7 @@ public class MHIntrinsicAllocFailureTest {
|
||||
// JIT compilers should be off, now.
|
||||
Asserts.assertNotEquals(WHITE_BOX.getCompilationActivityMode(), 1);
|
||||
System.out.println("Code cache segments for non-profiled and profiled nmethods are full.");
|
||||
// Generate and use a MH itrinsic. Should not trigger one of the following:
|
||||
// Generate and use a MH intrinsic. Should not trigger one of the following:
|
||||
// - VirtualMachineError: Out of space in CodeCache for method handle intrinsic
|
||||
// - InternalError: java.lang.NoSuchMethodException: no such method:
|
||||
// java.lang.invoke.MethodHandle.linkToStatic(int,int,Object,MemberName)int/invokeStatic
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -44,6 +44,27 @@
|
||||
* compiler.codecache.OverflowCodeCacheTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test OverflowCodeCacheTest
|
||||
* @bug 8059550 8279356 8326205
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary testing of code cache segments overflow
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:+TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M
|
||||
* -Xmixed -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.OverflowCodeCacheTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M
|
||||
* -Xmixed -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.OverflowCodeCacheTest
|
||||
*/
|
||||
|
||||
package compiler.codecache;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
@ -85,6 +106,7 @@ public class OverflowCodeCacheTest {
|
||||
System.out.println("allocating till possible...");
|
||||
ArrayList<Long> blobs = new ArrayList<>();
|
||||
int compilationActivityMode = -1;
|
||||
CodeCacheConstraints constraints = getCodeCacheConstraints(type);
|
||||
// Lock compilation to be able to better control code cache space
|
||||
WHITE_BOX.lockCompilation();
|
||||
try {
|
||||
@ -115,6 +137,7 @@ public class OverflowCodeCacheTest {
|
||||
} catch (VirtualMachineError e) {
|
||||
// Expected
|
||||
}
|
||||
constraints.check();
|
||||
// Free code cache space
|
||||
for (Long blob : blobs) {
|
||||
WHITE_BOX.freeCodeBlob(blob);
|
||||
@ -143,4 +166,31 @@ public class OverflowCodeCacheTest {
|
||||
return bean.getUsage().getMax();
|
||||
}
|
||||
|
||||
class CodeCacheConstraints {
|
||||
void check() {}
|
||||
}
|
||||
|
||||
CodeCacheConstraints getCodeCacheConstraints(final BlobType type) {
|
||||
if (Long.valueOf(0).equals(WHITE_BOX.getVMFlag("HotCodeHeapSize"))) {
|
||||
return new CodeCacheConstraints();
|
||||
} else if (BlobType.MethodHot == type) {
|
||||
// NonProfiledHeap is used when HotCodeHeap runs out of space.
|
||||
return new CodeCacheConstraints() {
|
||||
final int nonProfiledCount = WHITE_BOX.getCodeHeapEntries(BlobType.MethodNonProfiled.id).length;
|
||||
@Override
|
||||
void check() {
|
||||
Asserts.assertLT(nonProfiledCount, WHITE_BOX.getCodeHeapEntries(BlobType.MethodNonProfiled.id).length);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
// HotCodeHeap should not be used when other heap runs out of space.
|
||||
return new CodeCacheConstraints() {
|
||||
final int hotCount = WHITE_BOX.getCodeHeapEntries(BlobType.MethodHot.id).length;
|
||||
@Override
|
||||
void check() {
|
||||
Asserts.assertEQ(hotCount, WHITE_BOX.getCodeHeapEntries(BlobType.MethodHot.id).length);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -50,10 +50,16 @@ public class TestSegmentedCodeCacheOption {
|
||||
private static final String USE_SEGMENTED_CODE_CACHE
|
||||
= CommandLineOptionTest.prepareBooleanFlag(SEGMENTED_CODE_CACHE,
|
||||
true);
|
||||
private static final String UNLOCK_EXPERIMENTAL_VM_OPTIONS
|
||||
= CommandLineOptionTest.prepareBooleanFlag("UnlockExperimentalVMOptions", true);
|
||||
private static final String HOT_CODE_HEAP
|
||||
= CommandLineOptionTest.prepareBooleanFlag("HotCodeHeap", true);
|
||||
private static final long THRESHOLD_CC_SIZE_VALUE
|
||||
= CodeCacheOptions.mB(240);
|
||||
private static final long BELOW_THRESHOLD_CC_SIZE
|
||||
= THRESHOLD_CC_SIZE_VALUE - CodeCacheOptions.mB(1);
|
||||
private static final long HOT_CODE_HEAP_SIZE
|
||||
= CodeCacheOptions.mB(8);
|
||||
private static final String[] UNEXPECTED_MESSAGES = new String[] {
|
||||
".*" + SEGMENTED_CODE_CACHE + ".*"
|
||||
};
|
||||
@ -104,7 +110,7 @@ public class TestSegmentedCodeCacheOption {
|
||||
public void run() throws Throwable {
|
||||
// SCC is disabled w/o TieredCompilation by default
|
||||
String errorMessage = SEGMENTED_CODE_CACHE
|
||||
+ " should be disabled by default when tiered "
|
||||
+ " should be disabled by default when tiered "
|
||||
+ "compilation is disabled";
|
||||
|
||||
CommandLineOptionTest.verifyOptionValueForSameVM(
|
||||
@ -162,6 +168,52 @@ public class TestSegmentedCodeCacheOption {
|
||||
CommandLineOptionTest.prepareBooleanFlag(
|
||||
TIERED_COMPILATION, true));
|
||||
}
|
||||
},
|
||||
OPTION_VALUES_HOT {
|
||||
@Override
|
||||
public boolean isApplicable() {
|
||||
return Platform.isServer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() throws Throwable {
|
||||
// SCC is enabled w hot code heap w/o TieredCompilation
|
||||
String errorMessage = SEGMENTED_CODE_CACHE
|
||||
+ " should be enabled when the hot code heap "
|
||||
+ "is enabled";
|
||||
|
||||
CommandLineOptionTest.verifyOptionValueForSameVM(
|
||||
SEGMENTED_CODE_CACHE, "true", errorMessage,
|
||||
UNLOCK_EXPERIMENTAL_VM_OPTIONS,
|
||||
HOT_CODE_HEAP,
|
||||
CommandLineOptionTest.prepareNumericFlag(
|
||||
BlobType.MethodHot.sizeOptionName,
|
||||
HOT_CODE_HEAP_SIZE),
|
||||
CommandLineOptionTest.prepareBooleanFlag(
|
||||
TIERED_COMPILATION, false));
|
||||
|
||||
// Hot code heap could be explicitly enabled w/ SegmentedCodeCache
|
||||
// and w/ ReservedCodeCacheSize value below the threshold
|
||||
errorMessage = String.format("It should be possible to explicitly "
|
||||
+ "enable %s and %s with %s below threshold %d.",
|
||||
BlobType.MethodHot.sizeOptionName,
|
||||
SEGMENTED_CODE_CACHE,
|
||||
BlobType.All.sizeOptionName,
|
||||
THRESHOLD_CC_SIZE_VALUE);
|
||||
|
||||
CommandLineOptionTest.verifyOptionValueForSameVM(
|
||||
BlobType.MethodHot.sizeOptionName, String.valueOf(HOT_CODE_HEAP_SIZE),
|
||||
errorMessage,
|
||||
UNLOCK_EXPERIMENTAL_VM_OPTIONS,
|
||||
HOT_CODE_HEAP,
|
||||
CommandLineOptionTest.prepareNumericFlag(
|
||||
BlobType.All.sizeOptionName,
|
||||
BELOW_THRESHOLD_CC_SIZE),
|
||||
CommandLineOptionTest.prepareNumericFlag(
|
||||
BlobType.MethodHot.sizeOptionName,
|
||||
HOT_CODE_HEAP_SIZE),
|
||||
USE_SEGMENTED_CODE_CACHE);
|
||||
}
|
||||
};
|
||||
|
||||
TestCase() {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -69,5 +69,13 @@ public class GenericCodeHeapSizeRunner implements CodeCacheCLITestCase.Runner {
|
||||
BlobType.MethodProfiled.sizeOptionName,
|
||||
expectedValues.profiled),
|
||||
testCaseDescription.getTestOptions(options));
|
||||
|
||||
CommandLineOptionTest.verifyOptionValueForSameVM(
|
||||
BlobType.MethodHot.sizeOptionName,
|
||||
Long.toString(expectedValues.hot),
|
||||
String.format("%s should have value %d.",
|
||||
BlobType.MethodHot.sizeOptionName,
|
||||
expectedValues.hot),
|
||||
testCaseDescription.getTestOptions(options));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -48,13 +48,15 @@ import java.util.EnumSet;
|
||||
public class TestCodeHeapSizeOptions extends CodeCacheCLITestBase {
|
||||
private static final CodeCacheCLITestCase JVM_STARTUP
|
||||
= new CodeCacheCLITestCase(new CodeCacheCLITestCase.Description(
|
||||
options -> options.segmented,
|
||||
options -> options.segmented
|
||||
&& options.hot == 0,
|
||||
EnumSet.noneOf(BlobType.class)),
|
||||
new JVMStartupRunner());
|
||||
|
||||
private static final CodeCacheCLITestCase CODE_CACHE_FREE_SPACE
|
||||
= new CodeCacheCLITestCase(new CodeCacheCLITestCase.Description(
|
||||
options -> options.segmented
|
||||
&& options.hot == 0
|
||||
&& Platform.isDebugBuild(),
|
||||
EnumSet.noneOf(BlobType.class)),
|
||||
new CodeCacheFreeSpaceRunner());
|
||||
@ -65,13 +67,19 @@ public class TestCodeHeapSizeOptions extends CodeCacheCLITestBase {
|
||||
private TestCodeHeapSizeOptions() {
|
||||
super(CodeCacheCLITestBase.OPTIONS_SET,
|
||||
new CodeCacheCLITestCase(CodeCacheCLITestCase
|
||||
.CommonDescriptions.NON_TIERED.description,
|
||||
.CommonDescriptions.NON_TIERED_WO_HOT.description,
|
||||
GENERIC_RUNNER),
|
||||
new CodeCacheCLITestCase(CodeCacheCLITestCase
|
||||
.CommonDescriptions.TIERED_LEVEL_1.description,
|
||||
GENERIC_RUNNER),
|
||||
new CodeCacheCLITestCase(CodeCacheCLITestCase
|
||||
.CommonDescriptions.TIERED_LEVEL_4.description,
|
||||
.CommonDescriptions.TIERED_LEVEL_4_WO_HOT.description,
|
||||
GENERIC_RUNNER),
|
||||
new CodeCacheCLITestCase(CodeCacheCLITestCase
|
||||
.CommonDescriptions.NON_TIERED_W_HOT.description,
|
||||
GENERIC_RUNNER),
|
||||
new CodeCacheCLITestCase(CodeCacheCLITestCase
|
||||
.CommonDescriptions.TIERED_LEVEL_4_W_HOT.description,
|
||||
GENERIC_RUNNER),
|
||||
JVM_STARTUP,
|
||||
CODE_CACHE_FREE_SPACE);
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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
|
||||
@ -40,7 +40,13 @@ public class CodeCacheCLITestBase {
|
||||
CodeCacheOptions.mB(100)),
|
||||
new CodeCacheOptions(CodeCacheOptions.mB(60)),
|
||||
new CodeCacheOptions(CodeCacheOptions.mB(200)),
|
||||
new CodeCacheOptions(CodeCacheOptions.mB(300))
|
||||
new CodeCacheOptions(CodeCacheOptions.mB(300)),
|
||||
new CodeCacheOptions(CodeCacheOptions.mB(250),
|
||||
CodeCacheOptions.mB(50), CodeCacheOptions.mB(75),
|
||||
CodeCacheOptions.mB(75), CodeCacheOptions.mB(50)),
|
||||
new CodeCacheOptions(CodeCacheOptions.mB(200),
|
||||
CodeCacheOptions.mB(50), CodeCacheOptions.mB(100),
|
||||
CodeCacheOptions.mB(0), CodeCacheOptions.mB(50))
|
||||
};
|
||||
|
||||
private final CodeCacheCLITestCase[] testCases;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -39,15 +39,24 @@ import java.util.function.Function;
|
||||
* description.
|
||||
*/
|
||||
public class CodeCacheCLITestCase {
|
||||
private static final Function<CodeCacheOptions, Boolean> ONLY_SEGMENTED
|
||||
= options -> options.segmented;
|
||||
private static final Function<CodeCacheOptions, Boolean> SEGMENTED_SERVER
|
||||
= ONLY_SEGMENTED.andThen(isSegmented -> isSegmented
|
||||
private static final Function<CodeCacheOptions, Boolean> SEGMENTED_WO_HOT
|
||||
= options -> options.segmented && options.hot == 0;
|
||||
private static final Function<CodeCacheOptions, Boolean> SEGMENTED_SERVER_WO_HOT
|
||||
= SEGMENTED_WO_HOT.andThen(isSegmented -> isSegmented
|
||||
&& Platform.isServer() && Platform.isTieredSupported());
|
||||
private static final Function<CodeCacheOptions, Boolean> SEGMENTED_W_HOT
|
||||
= options -> options.segmented && options.hot > 0
|
||||
&& options.profiled > 0 && Platform.isTieredSupported();
|
||||
private static final Function<CodeCacheOptions, Boolean> SEGMENTED_W_HOT_WO_PROFILED
|
||||
= options -> options.segmented && options.hot > 0
|
||||
&& options.profiled == 0 && Platform.isTieredSupported();
|
||||
|
||||
private static final String USE_INT_MODE = "-Xint";
|
||||
private static final String SEGMENTED_CODE_CACHE = "SegmentedCodeCache";
|
||||
private static final String TIERED_COMPILATION = "TieredCompilation";
|
||||
private static final String TIERED_STOP_AT = "TieredStopAtLevel";
|
||||
private static final String UNLOCK_EXPERIMENTAL_VM_OPTIONS = "UnlockExperimentalVMOptions";
|
||||
private static final String HOT_CODE_HEAP = "HotCodeHeap";
|
||||
|
||||
private final Description description;
|
||||
private final Runner runner;
|
||||
@ -68,7 +77,7 @@ public class CodeCacheCLITestCase {
|
||||
* Verifies that in interpreted mode PrintCodeCache output contains
|
||||
* the whole code cache. Int mode disables SegmentedCodeCache with a warning.
|
||||
*/
|
||||
INT_MODE(ONLY_SEGMENTED, EnumSet.of(BlobType.All), USE_INT_MODE),
|
||||
INT_MODE(options -> options.hot == 0, EnumSet.of(BlobType.All), USE_INT_MODE),
|
||||
/**
|
||||
* Verifies that with disabled SegmentedCodeCache PrintCodeCache output
|
||||
* contains only CodeCache's entry.
|
||||
@ -81,7 +90,7 @@ public class CodeCacheCLITestCase {
|
||||
* code cache PrintCodeCache output does not contain information about
|
||||
* profiled-nmethods heap and non-segmented CodeCache.
|
||||
*/
|
||||
NON_TIERED(ONLY_SEGMENTED,
|
||||
NON_TIERED_WO_HOT(SEGMENTED_WO_HOT,
|
||||
EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled),
|
||||
CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION,
|
||||
false)),
|
||||
@ -90,7 +99,7 @@ public class CodeCacheCLITestCase {
|
||||
* warn about SegmentedCodeCache and contain information about all
|
||||
* heaps only.
|
||||
*/
|
||||
TIERED_LEVEL_0(SEGMENTED_SERVER,
|
||||
TIERED_LEVEL_0(SEGMENTED_SERVER_WO_HOT,
|
||||
EnumSet.of(BlobType.All),
|
||||
CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION,
|
||||
true),
|
||||
@ -100,19 +109,44 @@ public class CodeCacheCLITestCase {
|
||||
* contain information about non-nmethods and non-profiled nmethods
|
||||
* heaps only.
|
||||
*/
|
||||
TIERED_LEVEL_1(SEGMENTED_SERVER,
|
||||
TIERED_LEVEL_1(SEGMENTED_SERVER_WO_HOT,
|
||||
EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled),
|
||||
CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION,
|
||||
true),
|
||||
CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 1)),
|
||||
/**
|
||||
* Verifies that with TieredStopAtLevel=4 PrintCodeCache output will
|
||||
* contain information about all three code heaps.
|
||||
* contain information about non-nmethods, non-profiled nmethods
|
||||
* and profiled nmethods heaps only.
|
||||
*/
|
||||
TIERED_LEVEL_4(SEGMENTED_SERVER,
|
||||
EnumSet.complementOf(EnumSet.of(BlobType.All)),
|
||||
TIERED_LEVEL_4_WO_HOT(SEGMENTED_SERVER_WO_HOT,
|
||||
EnumSet.complementOf(EnumSet.of(BlobType.MethodHot, BlobType.All)),
|
||||
CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION,
|
||||
true),
|
||||
CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 4)),
|
||||
|
||||
/**
|
||||
* Verifies that with disabled tiered compilation and enabled hot code
|
||||
* cache PrintCodeCache output does not contain information about
|
||||
* profiled-nmethods heap and non-segmented CodeCache.
|
||||
*/
|
||||
NON_TIERED_W_HOT(SEGMENTED_W_HOT_WO_PROFILED,
|
||||
EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled, BlobType.MethodHot),
|
||||
CommandLineOptionTest.prepareBooleanFlag(UNLOCK_EXPERIMENTAL_VM_OPTIONS, true),
|
||||
CommandLineOptionTest.prepareBooleanFlag(HOT_CODE_HEAP, true),
|
||||
CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION,
|
||||
false)),
|
||||
|
||||
/**
|
||||
* Verifies that with TieredStopAtLevel=4 and hot code heap
|
||||
* PrintCodeCache output will contain information about non-nmethods,
|
||||
* non-profiled nmethods, profiled nmethods, and hot code heaps only.
|
||||
*/
|
||||
TIERED_LEVEL_4_W_HOT(SEGMENTED_W_HOT,
|
||||
EnumSet.complementOf(EnumSet.of(BlobType.All)),
|
||||
CommandLineOptionTest.prepareBooleanFlag(UNLOCK_EXPERIMENTAL_VM_OPTIONS, true),
|
||||
CommandLineOptionTest.prepareBooleanFlag(HOT_CODE_HEAP, true),
|
||||
CommandLineOptionTest.prepareBooleanFlag(TIERED_COMPILATION, true),
|
||||
CommandLineOptionTest.prepareNumericFlag(TIERED_STOP_AT, 4));
|
||||
|
||||
CommonDescriptions(Function<CodeCacheOptions, Boolean> predicate,
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -37,15 +37,20 @@ public class CodeCacheOptions {
|
||||
= EnumSet.of(BlobType.All);
|
||||
private static final EnumSet<BlobType> ALL_SEGMENTED_HEAPS
|
||||
= EnumSet.complementOf(NON_SEGMENTED_HEAPS);
|
||||
private static final EnumSet<BlobType> SEGMENTED_HEAPS_WO_PROFILED
|
||||
private static final EnumSet<BlobType> NON_NMETHOD_AND_NON_PROFILED_HEAPS
|
||||
= EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled);
|
||||
private static final EnumSet<BlobType> SEGMENTED_HEAPS_WO_HOT
|
||||
= EnumSet.of(BlobType.NonNMethod, BlobType.MethodProfiled, BlobType.MethodNonProfiled);
|
||||
private static final EnumSet<BlobType> ONLY_NON_METHODS_HEAP
|
||||
= EnumSet.of(BlobType.NonNMethod);
|
||||
private static final EnumSet<BlobType> NON_NMETHOD_AND_NON_PROFILED_AND_HOT_HEAPS
|
||||
= EnumSet.of(BlobType.NonNMethod, BlobType.MethodNonProfiled, BlobType.MethodHot);
|
||||
|
||||
public final long reserved;
|
||||
public final long nonNmethods;
|
||||
public final long nonProfiled;
|
||||
public final long profiled;
|
||||
public final long hot;
|
||||
public final boolean segmented;
|
||||
|
||||
public static long mB(long val) {
|
||||
@ -61,6 +66,7 @@ public class CodeCacheOptions {
|
||||
this.nonNmethods = 0;
|
||||
this.nonProfiled = 0;
|
||||
this.profiled = 0;
|
||||
this.hot = 0;
|
||||
this.segmented = false;
|
||||
}
|
||||
|
||||
@ -70,6 +76,17 @@ public class CodeCacheOptions {
|
||||
this.nonNmethods = nonNmethods;
|
||||
this.nonProfiled = nonProfiled;
|
||||
this.profiled = profiled;
|
||||
this.hot = 0;
|
||||
this.segmented = true;
|
||||
}
|
||||
|
||||
public CodeCacheOptions(long reserved, long nonNmethods, long nonProfiled,
|
||||
long profiled, long hot) {
|
||||
this.reserved = reserved;
|
||||
this.nonNmethods = nonNmethods;
|
||||
this.nonProfiled = nonProfiled;
|
||||
this.profiled = profiled;
|
||||
this.hot = hot;
|
||||
this.segmented = true;
|
||||
}
|
||||
|
||||
@ -83,6 +100,8 @@ public class CodeCacheOptions {
|
||||
return this.nonProfiled;
|
||||
case MethodProfiled:
|
||||
return this.profiled;
|
||||
case MethodHot:
|
||||
return this.hot;
|
||||
default:
|
||||
throw new Error("Unknown heap: " + heap.name());
|
||||
}
|
||||
@ -106,6 +125,11 @@ public class CodeCacheOptions {
|
||||
nonProfiled),
|
||||
CommandLineOptionTest.prepareNumericFlag(
|
||||
BlobType.MethodProfiled.sizeOptionName, profiled));
|
||||
if (hot > 0) {
|
||||
Collections.addAll(options,
|
||||
CommandLineOptionTest.prepareNumericFlag(
|
||||
BlobType.MethodHot.sizeOptionName, hot));
|
||||
}
|
||||
}
|
||||
return options.toArray(new String[options.size()]);
|
||||
}
|
||||
@ -113,9 +137,11 @@ public class CodeCacheOptions {
|
||||
public CodeCacheOptions mapOptions(EnumSet<BlobType> involvedCodeHeaps) {
|
||||
if (involvedCodeHeaps.isEmpty()
|
||||
|| involvedCodeHeaps.equals(NON_SEGMENTED_HEAPS)
|
||||
|| involvedCodeHeaps.equals(ALL_SEGMENTED_HEAPS)) {
|
||||
|| involvedCodeHeaps.equals(SEGMENTED_HEAPS_WO_HOT)
|
||||
|| involvedCodeHeaps.equals(ALL_SEGMENTED_HEAPS)
|
||||
|| involvedCodeHeaps.equals(NON_NMETHOD_AND_NON_PROFILED_AND_HOT_HEAPS)) {
|
||||
return this;
|
||||
} else if (involvedCodeHeaps.equals(SEGMENTED_HEAPS_WO_PROFILED)) {
|
||||
} else if (involvedCodeHeaps.equals(NON_NMETHOD_AND_NON_PROFILED_HEAPS)) {
|
||||
return new CodeCacheOptions(reserved, nonNmethods,
|
||||
profiled + nonProfiled, 0L);
|
||||
} else if (involvedCodeHeaps.equals(ONLY_NON_METHODS_HEAP)) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -46,7 +46,7 @@ import java.util.EnumSet;
|
||||
public class TestPrintCodeCacheOption extends CodeCacheCLITestBase {
|
||||
private static final CodeCacheCLITestCase DISABLED_PRINT_CODE_CACHE
|
||||
= new CodeCacheCLITestCase(new CodeCacheCLITestCase.Description(
|
||||
options -> true, EnumSet.noneOf(BlobType.class)),
|
||||
options -> options.hot == 0, EnumSet.noneOf(BlobType.class)),
|
||||
new PrintCodeCacheRunner(false));
|
||||
|
||||
private static final CodeCacheCLITestCase.Runner DEFAULT_RUNNER
|
||||
@ -61,7 +61,7 @@ public class TestPrintCodeCacheOption extends CodeCacheCLITestBase {
|
||||
.CommonDescriptions.NON_SEGMENTED.description,
|
||||
DEFAULT_RUNNER),
|
||||
new CodeCacheCLITestCase(CodeCacheCLITestCase
|
||||
.CommonDescriptions.NON_TIERED.description,
|
||||
.CommonDescriptions.NON_TIERED_WO_HOT.description,
|
||||
DEFAULT_RUNNER),
|
||||
new CodeCacheCLITestCase(CodeCacheCLITestCase
|
||||
.CommonDescriptions.TIERED_LEVEL_0.description,
|
||||
@ -70,7 +70,13 @@ public class TestPrintCodeCacheOption extends CodeCacheCLITestBase {
|
||||
.CommonDescriptions.TIERED_LEVEL_1.description,
|
||||
DEFAULT_RUNNER),
|
||||
new CodeCacheCLITestCase(CodeCacheCLITestCase
|
||||
.CommonDescriptions.TIERED_LEVEL_4.description,
|
||||
.CommonDescriptions.TIERED_LEVEL_4_WO_HOT.description,
|
||||
DEFAULT_RUNNER),
|
||||
new CodeCacheCLITestCase(CodeCacheCLITestCase
|
||||
.CommonDescriptions.NON_TIERED_W_HOT.description,
|
||||
DEFAULT_RUNNER),
|
||||
new CodeCacheCLITestCase(CodeCacheCLITestCase
|
||||
.CommonDescriptions.TIERED_LEVEL_4_W_HOT.description,
|
||||
DEFAULT_RUNNER),
|
||||
DISABLED_PRINT_CODE_CACHE);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -40,6 +40,26 @@
|
||||
* compiler.codecache.jmx.BeanTypeTest
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test BeanTypeTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary verify types of code cache memory pool bean
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @library /test/lib
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.BeanTypeTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.BeanTypeTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -40,6 +40,26 @@
|
||||
* compiler.codecache.jmx.CodeHeapBeanPresenceTest
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test CodeHeapBeanPresenceTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary verify CodeHeap bean presence
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @library /test/lib
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.CodeHeapBeanPresenceTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.CodeHeapBeanPresenceTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -42,6 +42,28 @@
|
||||
* compiler.codecache.jmx.GetUsageTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test GetUsageTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary testing of getUsage() for segmented code cache
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @library /test/lib /
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.GetUsageTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.GetUsageTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -42,6 +42,28 @@
|
||||
* compiler.codecache.jmx.InitialAndMaxUsageTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test InitialAndMaxUsageTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary testing of initial and max usage
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @library /test/lib /
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing
|
||||
* -XX:-MethodFlushing -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* -XX:CompileCommand=compileonly,null::* -XX:-UseLargePages
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.InitialAndMaxUsageTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing
|
||||
* -XX:-MethodFlushing -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* -XX:CompileCommand=compileonly,null::* -XX:-UseLargePages
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.InitialAndMaxUsageTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -40,6 +40,26 @@
|
||||
* compiler.codecache.jmx.ManagerNamesTest
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test ManagerNamesTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary verify getMemoryManageNames calls in case of segmented code cache
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @library /test/lib
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.ManagerNamesTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.ManagerNamesTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -40,6 +40,26 @@
|
||||
* compiler.codecache.jmx.MemoryPoolsPresenceTest
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test MemoryPoolsPresenceTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary verify that MemoryManagerMXBean exists for every code cache segment
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @library /test/lib
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.MemoryPoolsPresenceTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.MemoryPoolsPresenceTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -23,6 +23,8 @@
|
||||
|
||||
/*
|
||||
* @test PeakUsageTest
|
||||
* @summary testing of getPeakUsage() and resetPeakUsage for
|
||||
* segmented code cache
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
@ -37,8 +39,27 @@
|
||||
* -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:-SegmentedCodeCache
|
||||
* compiler.codecache.jmx.PeakUsageTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test PeakUsageTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary testing of getPeakUsage() and resetPeakUsage for
|
||||
* segmented code cache
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.PeakUsageTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.PeakUsageTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -40,6 +40,26 @@
|
||||
* compiler.codecache.jmx.PoolsIndependenceTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test PoolsIndependenceTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary testing of getUsageThreshold()
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @library /test/lib /
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.PoolsIndependenceTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.PoolsIndependenceTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -40,6 +40,26 @@
|
||||
* compiler.codecache.jmx.ThresholdNotificationsTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test ThresholdNotificationsTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary testing of getUsageThreshold()
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing
|
||||
* -XX:+WhiteBoxAPI -XX:-MethodFlushing -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.ThresholdNotificationsTest
|
||||
* @run main/othervm -XX:+UnlockDiagnosticVMOptions -Xbootclasspath/a:. -XX:-UseCodeCacheFlushing
|
||||
* -XX:+WhiteBoxAPI -XX:-MethodFlushing -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.ThresholdNotificationsTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -42,3 +42,26 @@
|
||||
* -XX:-SegmentedCodeCache
|
||||
* compiler.codecache.jmx.UsageThresholdExceededTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test UsageThresholdExceededSeveralTimesTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary verifying that getUsageThresholdCount() returns correct value
|
||||
* after threshold has been hit several times
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:CompileCommand=compileonly,null::* -Djdk.test.lib.iterations=10
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.UsageThresholdExceededTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:CompileCommand=compileonly,null::* -Djdk.test.lib.iterations=10
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.UsageThresholdExceededTest
|
||||
*/
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -32,17 +32,40 @@
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+SegmentedCodeCache
|
||||
* compiler.codecache.jmx.UsageThresholdExceededTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:-SegmentedCodeCache
|
||||
* compiler.codecache.jmx.UsageThresholdExceededTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test UsageThresholdExceededTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary verifying that getUsageThresholdCount() returns correct value
|
||||
* after threshold has been hit
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.UsageThresholdExceededTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.UsageThresholdExceededTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.whitebox.code.BlobType;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -42,6 +42,28 @@
|
||||
* compiler.codecache.jmx.UsageThresholdIncreasedTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test UsageThresholdIncreasedTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary verifying that threshold hasn't been hit after allocation smaller
|
||||
* than threshold value and that threshold value can be changed
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.UsageThresholdIncreasedTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.UsageThresholdIncreasedTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.whitebox.code.BlobType;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2022, 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
|
||||
@ -43,6 +43,29 @@
|
||||
* compiler.codecache.jmx.UsageThresholdNotExceededTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test UsageThresholdNotExceededTest
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary verifying that usage threshold not exceeded while allocating less
|
||||
* than usage threshold
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.UsageThresholdNotExceededTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI -XX:-UseCodeCacheFlushing -XX:-MethodFlushing
|
||||
* -XX:CompileCommand=compileonly,null::*
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.jmx.UsageThresholdNotExceededTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.jmx;
|
||||
|
||||
import jdk.test.whitebox.code.BlobType;
|
||||
|
||||
@ -43,6 +43,29 @@
|
||||
* compiler.codecache.stress.RandomAllocationTest
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test RandomAllocationTest
|
||||
* @key stress randomness
|
||||
* @requires vm.compiler2.enabled
|
||||
* @summary stressing code cache by allocating randomly sized "dummy" code blobs
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
*
|
||||
* @build jdk.test.whitebox.WhiteBox compiler.codecache.stress.Helper compiler.codecache.stress.TestCaseImpl
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:CompileCommand=dontinline,compiler.codecache.stress.Helper$TestCase::method
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:+TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.stress.RandomAllocationTest
|
||||
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
|
||||
* -XX:+WhiteBoxAPI
|
||||
* -XX:CompileCommand=dontinline,compiler.codecache.stress.Helper$TestCase::method
|
||||
* -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:HotCodeHeapSize=8M -XX:-TieredCompilation -XX:TieredStopAtLevel=4
|
||||
* compiler.codecache.stress.RandomAllocationTest
|
||||
*/
|
||||
|
||||
package compiler.codecache.stress;
|
||||
|
||||
import jdk.test.whitebox.code.BlobType;
|
||||
|
||||
@ -123,12 +123,10 @@ public class CPUFeaturesClearTest {
|
||||
if (isCpuFeatureSupported("sve2")) {
|
||||
outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSVE", 1)));
|
||||
outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sve2.*");
|
||||
verifyOutput(null, new String[]{"sve2"}, null, outputAnalyzer);
|
||||
}
|
||||
if (isCpuFeatureSupported("sve")) {
|
||||
outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSVE", 0)));
|
||||
outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sve.*");
|
||||
verifyOutput(null, new String[]{"sve"}, null, outputAnalyzer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,7 +26,6 @@
|
||||
* @library /test/lib /
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @requires (vm.cpu.features ~= ".*aes.*" | vm.cpu.features ~= ".*zvkn.*") & !vm.graal.enabled
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm/timeout=600 -Xbootclasspath/a:.
|
||||
|
||||
@ -81,7 +81,7 @@ public class TestAESIntrinsicsOnUnsupportedConfig extends AESIntrinsicsBase {
|
||||
|
||||
/**
|
||||
* Test checks following situation: <br/>
|
||||
* UseAESIntrinsics flag is set to true, TestAESMain is executed <br/>
|
||||
* UseAES flag is set to true, TestAESMain is executed <br/>
|
||||
* Expected result: UseAES flag is set to false <br/>
|
||||
* UseAES flag is set to false <br/>
|
||||
* Output shouldn't contain intrinsics usage <br/>
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
*/
|
||||
package compiler.exceptions;
|
||||
|
||||
import compiler.lib.ir_framework.CompLevel;
|
||||
import compiler.lib.ir_framework.Run;
|
||||
import compiler.lib.ir_framework.Test;
|
||||
import compiler.lib.ir_framework.TestFramework;
|
||||
@ -38,7 +39,7 @@ import test.java.lang.invoke.lib.InstructionHelper;
|
||||
/**
|
||||
* @test
|
||||
* @bug 8350208
|
||||
* @summary Safepoints added during the processing of exception handlers should never reexecute
|
||||
* @summary Safepoints added during the processing of exception handlers need correct stack state
|
||||
* @library /test/lib /test/jdk/java/lang/invoke/common /
|
||||
* @build test.java.lang.invoke.lib.InstructionHelper
|
||||
*
|
||||
@ -110,7 +111,7 @@ public class TestDebugDuringExceptionCatching {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(compLevel = CompLevel.C2) // see JDK-8381786
|
||||
private static int testBackwardHandler(V v) throws Throwable {
|
||||
return (int) SNIPPET_HANDLE.invokeExact(v);
|
||||
}
|
||||
|
||||
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib /
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -Xbatch -XX:-TieredCompilation -XX:+SegmentedCodeCache -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap
|
||||
* -XX:+NMethodRelocation -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:HotCodeIntervalSeconds=0 -XX:HotCodeCallLevel=0
|
||||
* -XX:HotCodeSampleSeconds=5 -XX:HotCodeStablePercent=-1 -XX:HotCodeSamplePercent=100 -XX:HotCodeStartupDelaySeconds=0
|
||||
* -XX:CompileCommand=compileonly,compiler.hotcode.HotCodeCollectorMoveFunction::func
|
||||
* compiler.hotcode.HotCodeCollectorMoveFunction
|
||||
*/
|
||||
|
||||
package compiler.hotcode;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import jdk.test.lib.Asserts;
|
||||
import jdk.test.whitebox.WhiteBox;
|
||||
import jdk.test.whitebox.code.BlobType;
|
||||
import jdk.test.whitebox.code.NMethod;
|
||||
|
||||
public class HotCodeCollectorMoveFunction {
|
||||
|
||||
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
|
||||
private static final Method method;
|
||||
private static final int C2_LEVEL = 4;
|
||||
private static final int FUNC_RUN_MILLIS = 60_000;
|
||||
|
||||
static {
|
||||
try {
|
||||
method = HotCodeCollectorMoveFunction.class.getMethod("func");
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
WHITE_BOX.testSetDontInlineMethod(method, true);
|
||||
|
||||
compileFunc();
|
||||
|
||||
// Call function so collector samples and relocates
|
||||
func();
|
||||
|
||||
// Function should now be in the Hot code heap after collector has had time to relocate
|
||||
NMethod reloc_nm = NMethod.get(method, false);
|
||||
Asserts.assertNotEquals(reloc_nm, null);
|
||||
Asserts.assertEQ(reloc_nm.code_blob_type, BlobType.MethodHot);
|
||||
}
|
||||
|
||||
public static void compileFunc() {
|
||||
WHITE_BOX.enqueueMethodForCompilation(method, C2_LEVEL);
|
||||
|
||||
if (WHITE_BOX.getMethodCompilationLevel(method) != C2_LEVEL) {
|
||||
throw new IllegalStateException("Method " + method + " is not compiled by C2.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void func() {
|
||||
long start = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() - start < FUNC_RUN_MILLIS) {}
|
||||
}
|
||||
|
||||
}
|
||||
167
test/hotspot/jtreg/compiler/hotcode/StressHotCodeCollector.java
Normal file
167
test/hotspot/jtreg/compiler/hotcode/StressHotCodeCollector.java
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @library /test/lib /
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm -Xbootclasspath/a:. -Xcomp -XX:-TieredCompilation -XX:+UnlockExperimentalVMOptions -XX:+HotCodeHeap -XX:+NMethodRelocation
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:HotCodeIntervalSeconds=0 -XX:HotCodeSampleSeconds=10
|
||||
* -XX:HotCodeStablePercent=-1 -XX:HotCodeSamplePercent=100 -XX:HotCodeStartupDelaySeconds=0
|
||||
* compiler.hotcode.StressHotCodeCollector
|
||||
*/
|
||||
|
||||
package compiler.hotcode;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
|
||||
import jdk.test.lib.compiler.InMemoryJavaCompiler;
|
||||
import jdk.test.whitebox.WhiteBox;
|
||||
|
||||
public class StressHotCodeCollector {
|
||||
|
||||
private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
|
||||
private static final double RUN_MILLIS = 60_000;
|
||||
|
||||
private static TestMethod[] methods = new TestMethod[100];
|
||||
|
||||
private static byte[] num1;
|
||||
private static byte[] num2;
|
||||
|
||||
private static byte[] genNum(Random random, int digitCount) {
|
||||
byte[] num = new byte[digitCount];
|
||||
int d;
|
||||
do {
|
||||
d = random.nextInt(10);
|
||||
} while (d == 0);
|
||||
|
||||
num[0] = (byte)d;
|
||||
for (int i = 1; i < digitCount; ++i) {
|
||||
num[i] = (byte)random.nextInt(10);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
private static void initNums() {
|
||||
final long seed = 8374592837465123L;
|
||||
Random random = new Random(seed);
|
||||
|
||||
final int digitCount = 40;
|
||||
num1 = genNum(random, digitCount);
|
||||
num2 = genNum(random, digitCount);
|
||||
}
|
||||
|
||||
private static void generateCode() throws Exception {
|
||||
byte[] result = new byte[num1.length + 1];
|
||||
|
||||
for (int i = 0; i < methods.length; i++) {
|
||||
methods[i] = new TestMethod();
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
initNums();
|
||||
generateCode();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
Random random = new Random();
|
||||
|
||||
while (System.currentTimeMillis() - start < RUN_MILLIS) {
|
||||
for (TestMethod m : methods) {
|
||||
if (random.nextInt(100) < 10) {
|
||||
m.deoptimize();
|
||||
}
|
||||
|
||||
byte[] result = new byte[num1.length + 1];
|
||||
m.invoke(num1, num2, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestMethod {
|
||||
private static final String CLASS_NAME = "A";
|
||||
private static final String METHOD_TO_COMPILE = "sum";
|
||||
private static final String JAVA_CODE = """
|
||||
public class A {
|
||||
|
||||
public static void sum(byte[] n1, byte[] n2, byte[] out) {
|
||||
long start = System.currentTimeMillis();
|
||||
while (System.currentTimeMillis() - start < 100) {}
|
||||
|
||||
final int digitCount = n1.length;
|
||||
int carry = 0;
|
||||
for (int i = digitCount - 1; i >= 0; --i) {
|
||||
int sum = n1[i] + n2[i] + carry;
|
||||
out[i] = (byte)(sum % 10);
|
||||
carry = sum / 10;
|
||||
}
|
||||
if (carry != 0) {
|
||||
for (int i = digitCount; i > 0; --i) {
|
||||
out[i] = out[i - 1];
|
||||
}
|
||||
out[0] = (byte)carry;
|
||||
}
|
||||
}
|
||||
}""";
|
||||
|
||||
private static final byte[] BYTE_CODE;
|
||||
|
||||
static {
|
||||
BYTE_CODE = InMemoryJavaCompiler.compile(CLASS_NAME, JAVA_CODE);
|
||||
}
|
||||
|
||||
private final Method method;
|
||||
|
||||
private static ClassLoader createClassLoaderFor() {
|
||||
return new ClassLoader() {
|
||||
@Override
|
||||
public Class<?> loadClass(String name) throws ClassNotFoundException {
|
||||
if (!name.equals(CLASS_NAME)) {
|
||||
return super.loadClass(name);
|
||||
}
|
||||
|
||||
return defineClass(name, BYTE_CODE, 0, BYTE_CODE.length);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public TestMethod() throws Exception {
|
||||
var cl = createClassLoaderFor().loadClass(CLASS_NAME);
|
||||
method = cl.getMethod(METHOD_TO_COMPILE, byte[].class, byte[].class, byte[].class);
|
||||
WHITE_BOX.testSetDontInlineMethod(method, true);
|
||||
}
|
||||
|
||||
public void invoke(byte[] num1, byte[] num2, byte[] result) throws Exception {
|
||||
method.invoke(null, num1, num2, result);
|
||||
}
|
||||
|
||||
public void deoptimize() {
|
||||
WHITE_BOX.deoptimizeMethod(method);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -71,7 +71,7 @@ public class TestVectorDoubleExpandShrink {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "2"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "2"})
|
||||
public static void testB128toB64(MemorySegment input, MemorySegment output) {
|
||||
vectorDoubleExpandShrink(BSPEC128, BSPEC64, input, output);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -38,7 +38,7 @@ import static compiler.vectorapi.reshape.utils.VectorReshapeHelper.*;
|
||||
*/
|
||||
public class TestVectorExpandShrink {
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testB64toB128(MemorySegment input, MemorySegment output) {
|
||||
vectorExpandShrink(BSPEC64, BSPEC128, input, output);
|
||||
}
|
||||
@ -71,7 +71,7 @@ public class TestVectorExpandShrink {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testB128toB64(MemorySegment input, MemorySegment output) {
|
||||
vectorExpandShrink(BSPEC128, BSPEC64, input, output);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -41,7 +41,7 @@ import static compiler.vectorapi.reshape.utils.VectorReshapeHelper.*;
|
||||
*/
|
||||
public class TestVectorRebracket {
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testB64toS64(byte[] input, short[] output) {
|
||||
vectorRebracket(BSPEC64, SSPEC64, input, output);
|
||||
}
|
||||
@ -52,7 +52,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testB64toI64(byte[] input, int[] output) {
|
||||
vectorRebracket(BSPEC64, ISPEC64, input, output);
|
||||
}
|
||||
@ -63,7 +63,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testB64toL64(byte[] input, long[] output) {
|
||||
vectorRebracket(BSPEC64, LSPEC64, input, output);
|
||||
}
|
||||
@ -74,7 +74,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testB64toF64(byte[] input, float[] output) {
|
||||
vectorRebracket(BSPEC64, FSPEC64, input, output);
|
||||
}
|
||||
@ -85,7 +85,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testB64toD64(byte[] input, double[] output) {
|
||||
vectorRebracket(BSPEC64, DSPEC64, input, output);
|
||||
}
|
||||
@ -96,7 +96,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testS64toB64(short[] input, byte[] output) {
|
||||
vectorRebracket(SSPEC64, BSPEC64, input, output);
|
||||
}
|
||||
@ -107,7 +107,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testS64toI64(short[] input, int[] output) {
|
||||
vectorRebracket(SSPEC64, ISPEC64, input, output);
|
||||
}
|
||||
@ -118,7 +118,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testS64toL64(short[] input, long[] output) {
|
||||
vectorRebracket(SSPEC64, LSPEC64, input, output);
|
||||
}
|
||||
@ -129,7 +129,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testS64toF64(short[] input, float[] output) {
|
||||
vectorRebracket(SSPEC64, FSPEC64, input, output);
|
||||
}
|
||||
@ -140,7 +140,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testS64toD64(short[] input, double[] output) {
|
||||
vectorRebracket(SSPEC64, DSPEC64, input, output);
|
||||
}
|
||||
@ -151,7 +151,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testI64toB64(int[] input, byte[] output) {
|
||||
vectorRebracket(ISPEC64, BSPEC64, input, output);
|
||||
}
|
||||
@ -162,7 +162,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testI64toS64(int[] input, short[] output) {
|
||||
vectorRebracket(ISPEC64, SSPEC64, input, output);
|
||||
}
|
||||
@ -173,7 +173,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testI64toL64(int[] input, long[] output) {
|
||||
vectorRebracket(ISPEC64, LSPEC64, input, output);
|
||||
}
|
||||
@ -184,7 +184,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testI64toF64(int[] input, float[] output) {
|
||||
vectorRebracket(ISPEC64, FSPEC64, input, output);
|
||||
}
|
||||
@ -195,7 +195,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testI64toD64(int[] input, double[] output) {
|
||||
vectorRebracket(ISPEC64, DSPEC64, input, output);
|
||||
}
|
||||
@ -206,7 +206,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testL64toB64(long[] input, byte[] output) {
|
||||
vectorRebracket(LSPEC64, BSPEC64, input, output);
|
||||
}
|
||||
@ -217,7 +217,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testL64toS64(long[] input, short[] output) {
|
||||
vectorRebracket(LSPEC64, SSPEC64, input, output);
|
||||
}
|
||||
@ -228,7 +228,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testL64toI64(long[] input, int[] output) {
|
||||
vectorRebracket(LSPEC64, ISPEC64, input, output);
|
||||
}
|
||||
@ -239,7 +239,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testL64toF64(long[] input, float[] output) {
|
||||
vectorRebracket(LSPEC64, FSPEC64, input, output);
|
||||
}
|
||||
@ -250,7 +250,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testL64toD64(long[] input, double[] output) {
|
||||
vectorRebracket(LSPEC64, DSPEC64, input, output);
|
||||
}
|
||||
@ -261,7 +261,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testF64toB64(float[] input, byte[] output) {
|
||||
vectorRebracket(FSPEC64, BSPEC64, input, output);
|
||||
}
|
||||
@ -272,7 +272,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testF64toS64(float[] input, short[] output) {
|
||||
vectorRebracket(FSPEC64, SSPEC64, input, output);
|
||||
}
|
||||
@ -283,7 +283,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testF64toI64(float[] input, int[] output) {
|
||||
vectorRebracket(FSPEC64, ISPEC64, input, output);
|
||||
}
|
||||
@ -294,7 +294,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testF64toL64(float[] input, long[] output) {
|
||||
vectorRebracket(FSPEC64, LSPEC64, input, output);
|
||||
}
|
||||
@ -305,7 +305,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testF64toD64(float[] input, double[] output) {
|
||||
vectorRebracket(FSPEC64, DSPEC64, input, output);
|
||||
}
|
||||
@ -316,7 +316,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testD64toB64(double[] input, byte[] output) {
|
||||
vectorRebracket(DSPEC64, BSPEC64, input, output);
|
||||
}
|
||||
@ -327,7 +327,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testD64toS64(double[] input, short[] output) {
|
||||
vectorRebracket(DSPEC64, SSPEC64, input, output);
|
||||
}
|
||||
@ -338,7 +338,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testD64toI64(double[] input, int[] output) {
|
||||
vectorRebracket(DSPEC64, ISPEC64, input, output);
|
||||
}
|
||||
@ -349,7 +349,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testD64toL64(double[] input, long[] output) {
|
||||
vectorRebracket(DSPEC64, LSPEC64, input, output);
|
||||
}
|
||||
@ -360,7 +360,7 @@ public class TestVectorRebracket {
|
||||
}
|
||||
|
||||
@Test
|
||||
@IR(counts = {REINTERPRET_NODE, "1"})
|
||||
@IR(applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}, counts = {REINTERPRET_NODE, "1"})
|
||||
public static void testD64toF64(double[] input, float[] output) {
|
||||
vectorRebracket(DSPEC64, FSPEC64, input, output);
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ import jdk.test.lib.process.OutputAnalyzer;
|
||||
* @requires vm.hasSA
|
||||
* @requires vm.gc != "Z"
|
||||
* @requires os.family == "linux"
|
||||
* @requires os.arch == "amd64"
|
||||
* @requires (os.arch == "amd64") | (os.arch == "aarch64")
|
||||
* @library /test/lib
|
||||
* @run driver TestJhsdbJstackMixedWithXComp
|
||||
*/
|
||||
@ -49,7 +49,7 @@ import jdk.test.lib.process.OutputAnalyzer;
|
||||
* @requires vm.hasSA
|
||||
* @requires vm.gc != "Z"
|
||||
* @requires os.family == "linux"
|
||||
* @requires os.arch == "amd64"
|
||||
* @requires (os.arch == "amd64") | (os.arch == "aarch64")
|
||||
* @library /test/lib
|
||||
* @run driver TestJhsdbJstackMixedWithXComp -XX:+PreserveFramePointer
|
||||
*/
|
||||
@ -60,7 +60,7 @@ import jdk.test.lib.process.OutputAnalyzer;
|
||||
* @requires vm.hasSA
|
||||
* @requires vm.gc != "Z"
|
||||
* @requires os.family == "linux"
|
||||
* @requires os.arch == "amd64"
|
||||
* @requires (os.arch == "amd64") | (os.arch == "aarch64")
|
||||
* @library /test/lib
|
||||
* @run driver TestJhsdbJstackMixedWithXComp -XX:-TieredCompilation
|
||||
*/
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -30,8 +30,8 @@
|
||||
* @modules java.net.http
|
||||
* java.logging
|
||||
* @build ALPNFailureTest
|
||||
* @run main/othervm -Djdk.internal.httpclient.debug=true ALPNFailureTest HTTP_1_1
|
||||
* @run main/othervm ALPNFailureTest HTTP_2
|
||||
* @run main/othervm -Djdk.internal.httpclient.debug=true ${test.main.class} HTTP_1_1
|
||||
* @run main/othervm ${test.main.class} HTTP_2
|
||||
*/
|
||||
import javax.net.ServerSocketFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,8 +31,8 @@
|
||||
* @build jdk.test.lib.net.SimpleSSLContext DigestEchoServer
|
||||
* jdk.httpclient.test.lib.common.HttpServerAdapters
|
||||
* ALPNFailureTest ALPNProxyFailureTest
|
||||
* @run main/othervm -Djdk.internal.httpclient.debug=true -Dtest.nolinger=true ALPNProxyFailureTest HTTP_1_1
|
||||
* @run main/othervm -Dtest.nolinger=true ALPNProxyFailureTest HTTP_2
|
||||
* @run main/othervm -Djdk.internal.httpclient.debug=true -Dtest.nolinger=true ${test.main.class} HTTP_1_1
|
||||
* @run main/othervm -Dtest.nolinger=true ${test.main.class} HTTP_2
|
||||
*/
|
||||
import javax.net.ServerSocketFactory;
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
* ReferenceTracker AggregateRequestBodyTest
|
||||
* @run junit/othervm -Djdk.internal.httpclient.debug=true
|
||||
* -Djdk.httpclient.HttpClient.log=requests,responses,errors,headers,frames
|
||||
* AggregateRequestBodyTest
|
||||
* ${test.main.class}
|
||||
* @summary Tests HttpRequest.BodyPublishers::concat
|
||||
*/
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@ import org.junit.jupiter.api.Test;
|
||||
*
|
||||
* @run junit/othervm -Djdk.internal.httpclient.debug=true
|
||||
* -Djdk.httpclient.HttpClient.log=requests,responses,errors
|
||||
* AltServiceUsageTest
|
||||
* ${test.main.class}
|
||||
*/
|
||||
public class AltServiceUsageTest implements HttpServerAdapters {
|
||||
|
||||
|
||||
@ -87,7 +87,7 @@ import org.junit.jupiter.params.provider.MethodSource;
|
||||
* jdk.test.lib.Platform jdk.test.lib.util.FileUtils
|
||||
* jdk.httpclient.test.lib.common.HttpServerAdapters
|
||||
* jdk.httpclient.test.lib.common.TestServerConfigurator
|
||||
* @run junit/othervm/timeout=480 AsFileDownloadTest
|
||||
* @run junit/othervm/timeout=480 ${test.main.class}
|
||||
*/
|
||||
public class AsFileDownloadTest {
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user