diff --git a/8065402-G1-does-not-expand-marking-stack-when-mark-s.patch b/8065402-G1-does-not-expand-marking-stack-when-mark-s.patch new file mode 100644 index 0000000..7bc0fdd --- /dev/null +++ b/8065402-G1-does-not-expand-marking-stack-when-mark-s.patch @@ -0,0 +1,96 @@ +From 21a76a7829958e0064051956d1d1f6ddb8b48650 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Mon, 24 Oct 2022 14:54:04 +0800 +Subject: [PATCH 28/33] I68TO2: 8065402: G1 does not expand marking stack when mark + stack overflow happens during concurrent marking +--- + .../vm/gc_implementation/g1/concurrentMark.cpp | 22 ++++++---------------- + .../vm/gc_implementation/g1/concurrentMark.hpp | 4 ---- + 2 files changed, 6 insertions(+), 20 deletions(-) + +diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +index 831ec94..df901a5 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp +@@ -247,7 +247,6 @@ bool CMMarkStack::allocate(size_t capacity) { + setEmpty(); + _capacity = (jint) capacity; + _saved_index = -1; +- _should_expand = false; + NOT_PRODUCT(_max_depth = 0); + return true; + } +@@ -256,8 +255,6 @@ void CMMarkStack::expand() { + // Called, during remark, if we've overflown the marking stack during marking. + assert(isEmpty(), "stack should been emptied while handling overflow"); + assert(_capacity <= (jint) MarkStackSizeMax, "stack bigger than permitted"); +- // Clear expansion flag +- _should_expand = false; + if (_capacity == (jint) MarkStackSizeMax) { + if (PrintGCDetails && Verbose) { + gclog_or_tty->print_cr(" (benign) Can't expand marking stack capacity, at max size limit"); +@@ -290,13 +287,6 @@ void CMMarkStack::expand() { + } + } + +-void CMMarkStack::set_should_expand() { +- // If we're resetting the marking state because of an +- // marking stack overflow, record that we should, if +- // possible, expand the stack. +- _should_expand = _cm->has_overflown(); +-} +- + CMMarkStack::~CMMarkStack() { + if (_base != NULL) { + _base = NULL; +@@ -795,8 +785,13 @@ void ConcurrentMark::reset() { + + + void ConcurrentMark::reset_marking_state(bool clear_overflow) { +- _markStack.set_should_expand(); + _markStack.setEmpty(); // Also clears the _markStack overflow flag ++ ++ // Expand the marking stack, if we have to and if we can. ++ if (has_overflown()) { ++ _markStack.expand(); ++ } ++ + if (clear_overflow) { + clear_has_overflown(); + } else { +@@ -1367,11 +1362,6 @@ void ConcurrentMark::checkpointRootsFinal(bool clear_all_soft_refs) { + set_non_marking_state(); + } + +- // Expand the marking stack, if we have to and if we can. +- if (_markStack.should_expand()) { +- _markStack.expand(); +- } +- + // Statistics + double now = os::elapsedTime(); + _remark_mark_times.add((mark_work_end - start) * 1000.0); +diff --git a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +index f78b1cb..bbd5d59 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.hpp +@@ -178,7 +178,6 @@ class CMMarkStack VALUE_OBJ_CLASS_SPEC { + NOT_PRODUCT(jint _max_depth;) // max depth plumbed during run + + bool _overflow; +- bool _should_expand; + DEBUG_ONLY(bool _drain_in_progress;) + DEBUG_ONLY(bool _drain_in_progress_yields;) + +@@ -255,9 +254,6 @@ class CMMarkStack VALUE_OBJ_CLASS_SPEC { + bool overflow() { return _overflow; } + void clear_overflow() { _overflow = false; } + +- bool should_expand() const { return _should_expand; } +- void set_should_expand(); +- + // Expand the stack, typically in response to an overflow condition + void expand(); + +-- +1.8.3.1 diff --git a/8140594-Various-minor-code-improvements-compiler.patch b/8140594-Various-minor-code-improvements-compiler.patch new file mode 100644 index 0000000..9c9881b --- /dev/null +++ b/8140594-Various-minor-code-improvements-compiler.patch @@ -0,0 +1,498 @@ +From 39f5104db20a569e361c0300756e35ab7e6ac296 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Fri, 16 Dec 2022 16:06:02 +0000 +Subject: [PATCH 30/33] I68TO2: 8140594: Various minor code improvements (compiler) +--- + hotspot/src/os/linux/vm/os_linux.cpp | 5 +- + hotspot/src/os/linux/vm/vmError_linux.cpp | 16 ++--- + hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp | 2 +- + hotspot/src/share/vm/adlc/formssel.cpp | 13 ++-- + hotspot/src/share/vm/c1/c1_LinearScan.cpp | 7 +- + hotspot/src/share/vm/classfile/classFileParser.cpp | 11 +-- + .../src/share/vm/classfile/systemDictionary.cpp | 6 +- + hotspot/src/share/vm/compiler/compileBroker.cpp | 84 +++++++--------------- + hotspot/src/share/vm/compiler/compileBroker.hpp | 11 +-- + hotspot/src/share/vm/compiler/compileLog.cpp | 3 +- + hotspot/src/share/vm/compiler/disassembler.cpp | 6 +- + hotspot/src/share/vm/oops/generateOopMap.cpp | 8 ++- + hotspot/src/share/vm/opto/block.cpp | 2 +- + hotspot/src/share/vm/opto/graphKit.cpp | 2 +- + hotspot/src/share/vm/opto/matcher.cpp | 9 ++- + hotspot/src/share/vm/runtime/relocator.cpp | 4 +- + 16 files changed, 84 insertions(+), 105 deletions(-) + +diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp +index ab28ee3..b82352c 100644 +--- a/hotspot/src/os/linux/vm/os_linux.cpp ++++ b/hotspot/src/os/linux/vm/os_linux.cpp +@@ -2159,9 +2159,10 @@ static bool _print_ascii_file(const char* filename, outputStream* st) { + return false; + } + +- char buf[32]; ++ char buf[33]; + int bytes; +- while ((bytes = ::read(fd, buf, sizeof(buf))) > 0) { ++ buf[32] = '\0'; ++ while ((bytes = ::read(fd, buf, sizeof(buf) - 1)) > 0) { + st->print_raw(buf, bytes); + } + +diff --git a/hotspot/src/os/linux/vm/vmError_linux.cpp b/hotspot/src/os/linux/vm/vmError_linux.cpp +index fca239c..52ca40b 100644 +--- a/hotspot/src/os/linux/vm/vmError_linux.cpp ++++ b/hotspot/src/os/linux/vm/vmError_linux.cpp +@@ -42,19 +42,19 @@ void VMError::show_message_box(char *buf, int buflen) { + char *p = &buf[len]; + + jio_snprintf(p, buflen - len, +- "\n\n" +- "Do you want to debug the problem?\n\n" +- "To debug, run 'gdb /proc/%d/exe %d'; then switch to thread " UINTX_FORMAT " (" INTPTR_FORMAT ")\n" +- "Enter 'yes' to launch gdb automatically (PATH must include gdb)\n" +- "Otherwise, press RETURN to abort...", +- os::current_process_id(), os::current_process_id(), +- os::current_thread_id(), os::current_thread_id()); ++ "\n\n" ++ "Do you want to debug the problem?\n\n" ++ "To debug, run 'gdb /proc/%d/exe %d'; then switch to thread " UINTX_FORMAT " (" INTPTR_FORMAT ")\n" ++ "Enter 'yes' to launch gdb automatically (PATH must include gdb)\n" ++ "Otherwise, press RETURN to abort...", ++ os::current_process_id(), os::current_process_id(), ++ os::current_thread_id(), os::current_thread_id()); + + yes = os::message_box("Unexpected Error", buf); + + if (yes) { + // yes, user asked VM to launch debugger +- jio_snprintf(buf, buflen, "gdb /proc/%d/exe %d", ++ jio_snprintf(buf, sizeof(char)*buflen, "gdb /proc/%d/exe %d", + os::current_process_id(), os::current_process_id()); + + os::fork_and_exec(buf); +diff --git a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +index 4775dc8..fba3d28 100644 +--- a/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp ++++ b/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp +@@ -813,7 +813,7 @@ void os::print_context(outputStream *st, void *context) { + + intptr_t *sp = (intptr_t *)os::Linux::ucontext_get_sp(uc); + st->print_cr("Top of Stack: (sp=" PTR_FORMAT ")", sp); +- print_hex_dump(st, (address)sp, (address)(sp + 8*sizeof(intptr_t)), sizeof(intptr_t)); ++ print_hex_dump(st, (address)sp, (address)(sp + 8), sizeof(intptr_t)); + st->cr(); + + // Note: it may be unsafe to inspect memory near pc. For example, pc may +diff --git a/hotspot/src/share/vm/adlc/formssel.cpp b/hotspot/src/share/vm/adlc/formssel.cpp +index 23fa1bb..6d57ff2 100644 +--- a/hotspot/src/share/vm/adlc/formssel.cpp ++++ b/hotspot/src/share/vm/adlc/formssel.cpp +@@ -1496,7 +1496,8 @@ void MachNodeForm::output(FILE *fp) { + // twice, we need to check that the operands are pointer-eequivalent in + // the DFA during the labeling process. + Predicate *InstructForm::build_predicate() { +- char buf[1024], *s=buf; ++ const int buflen = 1024; ++ char buf[buflen], *s=buf; + Dict names(cmpstr,hashstr,Form::arena); // Map Names to counts + + MatchNode *mnode = +@@ -1505,12 +1506,12 @@ Predicate *InstructForm::build_predicate() { + + uint first = 1; + // Start with the predicate supplied in the .ad file. +- if( _predicate ) { +- if( first ) first=0; +- strcpy(s,"("); s += strlen(s); +- strcpy(s,_predicate->_pred); ++ if(_predicate) { ++ if(first) first = 0; ++ strcpy(s, "("); s += strlen(s); ++ strncpy(s, _predicate->_pred, buflen - strlen(s) - 1); + s += strlen(s); +- strcpy(s,")"); s += strlen(s); ++ strcpy(s, ")"); s += strlen(s); + } + for( DictI i(&names); i.test(); ++i ) { + uintptr_t cnt = (uintptr_t)i._value; +diff --git a/hotspot/src/share/vm/c1/c1_LinearScan.cpp b/hotspot/src/share/vm/c1/c1_LinearScan.cpp +index ec4a67e..d754aa9 100644 +--- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp ++++ b/hotspot/src/share/vm/c1/c1_LinearScan.cpp +@@ -5484,7 +5484,7 @@ int LinearScanWalker::find_locked_double_reg(int reg_needed_until, int interval_ + } + } + +- if (_block_pos[max_reg] <= interval_to || _block_pos[max_reg + 1] <= interval_to) { ++ if (max_reg != any_reg && (_block_pos[max_reg] <= interval_to || _block_pos[max_reg + 1] <= interval_to)) { + *need_split = true; + } + +@@ -6443,8 +6443,9 @@ void LinearScanStatistic::print(const char* title) { + if (_counters_sum[i] > 0 || _counters_max[i] >= 0) { + tty->print("%25s: %8d", counter_name(i), _counters_sum[i]); + +- if (base_counter(i) != invalid_counter) { +- tty->print(" (%5.1f%%) ", _counters_sum[i] * 100.0 / _counters_sum[base_counter(i)]); ++ LinearScanStatistic::Counter cntr = base_counter(i); ++ if (cntr != invalid_counter) { ++ tty->print(" (%5.1f%%) ", _counters_sum[i] * 100.0 / _counters_sum[cntr]); + } else { + tty->print(" "); + } +diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp +index 51ab4f5..d8e99e6 100644 +--- a/hotspot/src/share/vm/classfile/classFileParser.cpp ++++ b/hotspot/src/share/vm/classfile/classFileParser.cpp +@@ -1085,9 +1085,11 @@ class FieldAllocationCount: public ResourceObj { + + FieldAllocationType update(bool is_static, BasicType type) { + FieldAllocationType atype = basic_type_to_atype(is_static, type); +- // Make sure there is no overflow with injected fields. +- assert(count[atype] < 0xFFFF, "More than 65535 fields"); +- count[atype]++; ++ if (atype != BAD_ALLOCATION_TYPE) { ++ // Make sure there is no overflow with injected fields. ++ assert(count[atype] < 0xFFFF, "More than 65535 fields"); ++ count[atype]++; ++ } + return atype; + } + }; +@@ -3087,8 +3089,9 @@ void ClassFileParser::parse_classfile_attributes(ClassFileParser::ClassAnnotatio + } + } else if (tag == vmSymbols::tag_bootstrap_methods() && + _major_version >= Verifier::INVOKEDYNAMIC_MAJOR_VERSION) { +- if (parsed_bootstrap_methods_attribute) ++ if (parsed_bootstrap_methods_attribute) { + classfile_parse_error("Multiple BootstrapMethods attributes in class file %s", CHECK); ++ } + parsed_bootstrap_methods_attribute = true; + parse_classfile_bootstrap_methods_attribute(attribute_length, CHECK); + } else if (tag == vmSymbols::tag_runtime_visible_type_annotations()) { +diff --git a/hotspot/src/share/vm/classfile/systemDictionary.cpp b/hotspot/src/share/vm/classfile/systemDictionary.cpp +index d02ed31..9089a76 100644 +--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp ++++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp +@@ -1195,10 +1195,10 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name, + while ((index = strchr(name, '/')) != NULL) { + *index = '.'; // replace '/' with '.' in package name + } +- const char* fmt = "Prohibited package name: %s"; +- size_t len = strlen(fmt) + strlen(name); ++ const char* msg_text = "Prohibited package name: "; ++ size_t len = strlen(msg_text) + strlen(name) + 1; + char* message = NEW_RESOURCE_ARRAY(char, len); +- jio_snprintf(message, len, fmt, name); ++ jio_snprintf(message, len, "%s%s", msg_text, name); + Exceptions::_throw_msg(THREAD_AND_LOCATION, + vmSymbols::java_lang_SecurityException(), message); + } +diff --git a/hotspot/src/share/vm/compiler/compileBroker.cpp b/hotspot/src/share/vm/compiler/compileBroker.cpp +index 0e9af0d..7963625 100644 +--- a/hotspot/src/share/vm/compiler/compileBroker.cpp ++++ b/hotspot/src/share/vm/compiler/compileBroker.cpp +@@ -136,11 +136,6 @@ AbstractCompiler* CompileBroker::_compilers[2]; + volatile jint CompileBroker::_compilation_id = 0; + volatile jint CompileBroker::_osr_compilation_id = 0; + +-// Debugging information +-int CompileBroker::_last_compile_type = no_compile; +-int CompileBroker::_last_compile_level = CompLevel_none; +-char CompileBroker::_last_method_compiled[CompileBroker::name_buffer_length]; +- + // Performance counters + PerfCounter* CompileBroker::_perf_total_compilation = NULL; + PerfCounter* CompileBroker::_perf_osr_compilation = NULL; +@@ -882,8 +877,6 @@ CompilerCounters::CompilerCounters(const char* thread_name, int instance, TRAPS) + // + // Initialize the Compilation object + void CompileBroker::compilation_init() { +- _last_method_compiled[0] = '\0'; +- + // No need to initialize compilation system if we do not use it. + if (!UseCompiler) { + return; +@@ -1964,8 +1957,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { + } + assert(!method->is_native(), "no longer compile natives"); + +- // Save information about this method in case of failure. +- set_last_compile(thread, method, is_osr, task_level); ++ // Update compile information when using perfdata. ++ if (UsePerfData) { ++ update_compile_perf_data(thread, method, is_osr); ++ } + + DTRACE_METHOD_COMPILE_BEGIN_PROBE(method, compiler_name(task_level)); + } +@@ -2180,52 +2175,44 @@ void CompileBroker::handle_full_code_cache() { + // CompileBroker::set_last_compile + // + // Record this compilation for debugging purposes. +-void CompileBroker::set_last_compile(CompilerThread* thread, methodHandle method, bool is_osr, int comp_level) { ++void CompileBroker::update_compile_perf_data(CompilerThread* thread, const methodHandle& method, bool is_osr) { + ResourceMark rm; + char* method_name = method->name()->as_C_string(); +- strncpy(_last_method_compiled, method_name, CompileBroker::name_buffer_length); +- _last_method_compiled[CompileBroker::name_buffer_length - 1] = '\0'; // ensure null terminated + char current_method[CompilerCounters::cmname_buffer_length]; + size_t maxLen = CompilerCounters::cmname_buffer_length; + +- if (UsePerfData) { +- const char* class_name = method->method_holder()->name()->as_C_string(); ++ const char* class_name = method->method_holder()->name()->as_C_string(); + +- size_t s1len = strlen(class_name); +- size_t s2len = strlen(method_name); ++ size_t s1len = strlen(class_name); ++ size_t s2len = strlen(method_name); + +- // check if we need to truncate the string +- if (s1len + s2len + 2 > maxLen) { ++ // check if we need to truncate the string ++ if (s1len + s2len + 2 > maxLen) { + +- // the strategy is to lop off the leading characters of the +- // class name and the trailing characters of the method name. ++ // the strategy is to lop off the leading characters of the ++ // class name and the trailing characters of the method name. + +- if (s2len + 2 > maxLen) { +- // lop of the entire class name string, let snprintf handle +- // truncation of the method name. +- class_name += s1len; // null string +- } +- else { +- // lop off the extra characters from the front of the class name +- class_name += ((s1len + s2len + 2) - maxLen); +- } ++ if (s2len + 2 > maxLen) { ++ // lop of the entire class name string, let snprintf handle ++ // truncation of the method name. ++ class_name += s1len; // null string ++ } ++ else { ++ // lop off the extra characters from the front of the class name ++ class_name += ((s1len + s2len + 2) - maxLen); + } +- +- jio_snprintf(current_method, maxLen, "%s %s", class_name, method_name); + } + ++ jio_snprintf(current_method, maxLen, "%s %s", class_name, method_name); ++ ++ int last_compile_type = normal_compile; + if (CICountOSR && is_osr) { +- _last_compile_type = osr_compile; +- } else { +- _last_compile_type = normal_compile; ++ last_compile_type = normal_compile; + } +- _last_compile_level = comp_level; + +- if (UsePerfData) { +- CompilerCounters* counters = thread->counters(); +- counters->set_current_method(current_method); +- counters->set_compile_type((jlong)_last_compile_type); +- } ++ CompilerCounters* counters = thread->counters(); ++ counters->set_current_method(current_method); ++ counters->set_compile_type((jlong) last_compile_type); + } + + +@@ -2417,23 +2404,6 @@ void CompileBroker::print_times() { + tty->print_cr(" nmethod total size : %6d bytes", CompileBroker::_sum_nmethod_size); + } + +-// Debugging output for failure +-void CompileBroker::print_last_compile() { +- if ( _last_compile_level != CompLevel_none && +- compiler(_last_compile_level) != NULL && +- _last_method_compiled != NULL && +- _last_compile_type != no_compile) { +- if (_last_compile_type == osr_compile) { +- tty->print_cr("Last parse: [osr]%d+++(%d) %s", +- _osr_compilation_id, _last_compile_level, _last_method_compiled); +- } else { +- tty->print_cr("Last parse: %d+++(%d) %s", +- _compilation_id, _last_compile_level, _last_method_compiled); +- } +- } +-} +- +- + void CompileBroker::print_compiler_threads_on(outputStream* st) { + #ifndef PRODUCT + st->print_cr("Compiler thread printing unimplemented."); +diff --git a/hotspot/src/share/vm/compiler/compileBroker.hpp b/hotspot/src/share/vm/compiler/compileBroker.hpp +index 16e0ba3..96d5e81 100644 +--- a/hotspot/src/share/vm/compiler/compileBroker.hpp ++++ b/hotspot/src/share/vm/compiler/compileBroker.hpp +@@ -265,7 +265,7 @@ class CompileBroker: AllStatic { + name_buffer_length = 100 + }; + +- // Compile type Information for print_last_compile() and CompilerCounters ++ // Compile type Information for CompilerCounters + enum { no_compile, normal_compile, osr_compile, native_compile }; + static int assign_compile_id (methodHandle method, int osr_bci); + +@@ -284,10 +284,6 @@ class CompileBroker: AllStatic { + static volatile jint _compilation_id; + static volatile jint _osr_compilation_id; + +- static int _last_compile_type; +- static int _last_compile_level; +- static char _last_method_compiled[name_buffer_length]; +- + static CompileQueue* _c2_compile_queue; + static CompileQueue* _c1_compile_queue; + +@@ -356,7 +352,7 @@ class CompileBroker: AllStatic { + static void wait_for_completion(CompileTask* task); + + static void invoke_compiler_on_method(CompileTask* task); +- static void set_last_compile(CompilerThread *thread, methodHandle method, bool is_osr, int comp_level); ++ static void update_compile_perf_data(CompilerThread *thread, const methodHandle& method, bool is_osr); + static void push_jni_handle_block(); + static void pop_jni_handle_block(); + static bool check_break_at(methodHandle method, int compile_id, bool is_osr); +@@ -454,9 +450,6 @@ class CompileBroker: AllStatic { + // Print a detailed accounting of compilation time + static void print_times(); + +- // Debugging output for failure +- static void print_last_compile(); +- + static void print_compiler_threads_on(outputStream* st); + + // compiler name for debugging +diff --git a/hotspot/src/share/vm/compiler/compileLog.cpp b/hotspot/src/share/vm/compiler/compileLog.cpp +index 0637fd0..7dd9b46 100644 +--- a/hotspot/src/share/vm/compiler/compileLog.cpp ++++ b/hotspot/src/share/vm/compiler/compileLog.cpp +@@ -221,7 +221,8 @@ void CompileLog::finish_log_on_error(outputStream* file, char* buf, int buflen) + // Copy any remaining data inside a quote: + bool saw_slop = false; + int end_cdata = 0; // state machine [0..2] watching for too many "]]" +- while ((nr = read(partial_fd, buf, buflen)) > 0) { ++ while ((nr = read(partial_fd, buf, buflen-1)) > 0) { ++ buf[buflen-1] = '\0'; + if (!saw_slop) { + file->print_raw_cr(""); + file->print_raw_cr("= 0) { + // 2. /jre/lib///hsdis-.so + strcpy(&buf[lib_offset], hsdis_library_name); + strcat(&buf[lib_offset], os::dll_file_extension()); + _library = os::dll_load(buf, ebuf, sizeof ebuf); + } +- if (_library == NULL) { ++ if (_library == NULL && lib_offset > 0) { + // 3. /jre/lib//hsdis-.so + buf[lib_offset - 1] = '\0'; + const char* p = strrchr(buf, *os::file_separator()); +diff --git a/hotspot/src/share/vm/oops/generateOopMap.cpp b/hotspot/src/share/vm/oops/generateOopMap.cpp +index bb951f8..8452f96 100644 +--- a/hotspot/src/share/vm/oops/generateOopMap.cpp ++++ b/hotspot/src/share/vm/oops/generateOopMap.cpp +@@ -1684,7 +1684,13 @@ void GenerateOopMap::ppdupswap(int poplen, const char *out) { + assert(poplen < 5, "this must be less than length of actual vector"); + + // pop all arguments +- for(int i = 0; i < poplen; i++) actual[i] = pop(); ++ for (int i = 0; i < poplen; i++) { ++ actual[i] = pop(); ++ } ++ // Field _state is uninitialized when calling push. ++ for (int i = poplen; i < 5; i++) { ++ actual[i] = CellTypeState::uninit; ++ } + + // put them back + char push_ch = *out++; +diff --git a/hotspot/src/share/vm/opto/block.cpp b/hotspot/src/share/vm/opto/block.cpp +index 245ce42..1789d49 100644 +--- a/hotspot/src/share/vm/opto/block.cpp ++++ b/hotspot/src/share/vm/opto/block.cpp +@@ -1430,7 +1430,7 @@ void PhaseBlockLayout::find_edges() { + if (n->num_preds() != 1) break; + + i++; +- assert(n = _cfg.get_block(i), "expecting next block"); ++ assert(n == _cfg.get_block(i), "expecting next block"); + tr->append(n); + uf->map(n->_pre_order, tr->id()); + traces[n->_pre_order] = NULL; +diff --git a/hotspot/src/share/vm/opto/graphKit.cpp b/hotspot/src/share/vm/opto/graphKit.cpp +index f7c1009..dfadd3e 100644 +--- a/hotspot/src/share/vm/opto/graphKit.cpp ++++ b/hotspot/src/share/vm/opto/graphKit.cpp +@@ -1074,7 +1074,7 @@ bool GraphKit::compute_stack_effects(int& inputs, int& depth) { + case Bytecodes::_freturn: + case Bytecodes::_dreturn: + case Bytecodes::_areturn: +- assert(rsize = -depth, ""); ++ assert(rsize == -depth, ""); + inputs = rsize; + break; + +diff --git a/hotspot/src/share/vm/opto/matcher.cpp b/hotspot/src/share/vm/opto/matcher.cpp +index b26015c..11e11e0 100644 +--- a/hotspot/src/share/vm/opto/matcher.cpp ++++ b/hotspot/src/share/vm/opto/matcher.cpp +@@ -659,11 +659,14 @@ void Matcher::Fixup_Save_On_Entry( ) { + uint reth_edge_cnt = TypeFunc::Parms+1; + RegMask *reth_rms = init_input_masks( reth_edge_cnt + soe_cnt, _return_addr_mask, c_frame_ptr_mask ); + // Rethrow takes exception oop only, but in the argument 0 slot. +- reth_rms[TypeFunc::Parms] = mreg2regmask[find_receiver(false)]; ++ OptoReg::Name reg = find_receiver(false); ++ if (reg >= 0) { ++ reth_rms[TypeFunc::Parms] = mreg2regmask[reg]; + #ifdef _LP64 +- // Need two slots for ptrs in 64-bit land +- reth_rms[TypeFunc::Parms].Insert(OptoReg::add(OptoReg::Name(find_receiver(false)),1)); ++ // Need two slots for ptrs in 64-bit land ++ reth_rms[TypeFunc::Parms].Insert(OptoReg::add(OptoReg::Name(reg), 1)); + #endif ++ } + + // Input RegMask array shared by all TailCalls + uint tail_call_edge_cnt = TypeFunc::Parms+2; +diff --git a/hotspot/src/share/vm/runtime/relocator.cpp b/hotspot/src/share/vm/runtime/relocator.cpp +index 450bcf2..2bbb8db 100644 +--- a/hotspot/src/share/vm/runtime/relocator.cpp ++++ b/hotspot/src/share/vm/runtime/relocator.cpp +@@ -612,8 +612,8 @@ bool Relocator::relocate_code(int bci, int ilen, int delta) { + // In case we have shrunken a tableswitch/lookupswitch statement, we store the last + // bytes that get overwritten. We have to copy the bytes after the change_jumps method + // has been called, since it is likly to update last offset in a tableswitch/lookupswitch +- if (delta < 0) { +- assert(delta>=-3, "we cannot overwrite more than 3 bytes"); ++ assert(delta >= -3, "We cannot overwrite more than 3 bytes."); ++ if (delta < 0 && delta >= -3) { + memcpy(_overwrite, addr_at(bci + ilen + delta), -delta); + } + +-- +1.8.3.1 diff --git a/8189688-NMT-Report-per-class-load-metadata-informati.patch b/8189688-NMT-Report-per-class-load-metadata-informati.patch new file mode 100644 index 0000000..63dbfa5 --- /dev/null +++ b/8189688-NMT-Report-per-class-load-metadata-informati.patch @@ -0,0 +1,561 @@ +From 528a3b6459e34532120f468ba9afb8833d516f5a Mon Sep 17 00:00:00 2001 +From: eapen +Date: Thu, 15 Dec 2022 11:38:55 +0800 +Subject: [PATCH 19/33] I68TO2: 8189688: NMT: Report per-class load metadata + information +--- + hotspot/src/share/vm/memory/metaspace.cpp | 322 ++++++++++++++++++++++++- + hotspot/src/share/vm/memory/metaspace.hpp | 4 + + hotspot/src/share/vm/runtime/vm_operations.cpp | 4 + + hotspot/src/share/vm/runtime/vm_operations.hpp | 12 + + hotspot/src/share/vm/services/nmtDCmd.cpp | 16 +- + hotspot/src/share/vm/services/nmtDCmd.hpp | 1 + + 6 files changed, 354 insertions(+), 5 deletions(-) + +diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp +index 6c4654b..cf4a112 100644 +--- a/hotspot/src/share/vm/memory/metaspace.cpp ++++ b/hotspot/src/share/vm/memory/metaspace.cpp +@@ -75,6 +75,22 @@ enum ChunkIndex { + NumberOfInUseLists = 4 + }; + ++// Helper, returns a descriptive name for the given index. ++static const char* chunk_size_name(ChunkIndex index) { ++ switch (index) { ++ case SpecializedIndex: ++ return "specialized"; ++ case SmallIndex: ++ return "small"; ++ case MediumIndex: ++ return "medium"; ++ case HumongousIndex: ++ return "humongous"; ++ default: ++ return "Invalid index"; ++ } ++} ++ + enum ChunkSizes { // in words. + ClassSpecializedChunk = 128, + SpecializedChunk = 128, +@@ -89,6 +105,18 @@ static ChunkIndex next_chunk_index(ChunkIndex i) { + return (ChunkIndex) (i+1); + } + ++static const char* scale_unit(size_t scale) { ++ switch(scale) { ++ case 1: return "BYTES"; ++ case K: return "KB"; ++ case M: return "MB"; ++ case G: return "GB"; ++ default: ++ ShouldNotReachHere(); ++ return NULL; ++ } ++} ++ + volatile intptr_t MetaspaceGC::_capacity_until_GC = 0; + uint MetaspaceGC::_shrink_factor = 0; + bool MetaspaceGC::_should_concurrent_collect = false; +@@ -141,6 +169,18 @@ class ChunkManager : public CHeapObj { + } + void verify_free_chunks_count(); + ++ struct ChunkManagerStatistics { ++ size_t num_by_type[NumberOfFreeLists]; ++ size_t single_size_by_type[NumberOfFreeLists]; ++ size_t total_size_by_type[NumberOfFreeLists]; ++ size_t num_humongous_chunks; ++ size_t total_size_humongous_chunks; ++ }; ++ ++ void locked_get_statistics(ChunkManagerStatistics* stat) const; ++ void get_statistics(ChunkManagerStatistics* stat) const; ++ static void print_statistics(const ChunkManagerStatistics* stat, outputStream* out, size_t scale); ++ + public: + + ChunkManager(size_t specialized_size, size_t small_size, size_t medium_size) +@@ -157,6 +197,9 @@ class ChunkManager : public CHeapObj { + // for special, small, medium, and humongous chunks. + ChunkIndex list_index(size_t size); + ++ // Map a given index to the chunk size. ++ size_t size_by_index(ChunkIndex index) const; ++ + // Remove the chunk from its freelist. It is + // expected to be on one of the _free_chunks[] lists. + void remove_chunk(Metachunk* chunk); +@@ -249,6 +292,10 @@ class ChunkManager : public CHeapObj { + void locked_print_sum_free_chunks(outputStream* st); + + void print_on(outputStream* st) const; ++ ++ // Prints composition for both non-class and (if available) ++ // class chunk manager. ++ static void print_all_chunkmanagers(outputStream* out, size_t scale = 1); + }; + + // Used to manage the free list of Metablocks (a block corresponds +@@ -1707,7 +1754,6 @@ bool Metadebug::test_metadata_failure() { + #endif + + // ChunkManager methods +- + size_t ChunkManager::free_chunks_total_words() { + return _free_chunks_total; + } +@@ -1729,6 +1775,12 @@ size_t ChunkManager::free_chunks_count() { + return _free_chunks_count; + } + ++size_t ChunkManager::size_by_index(ChunkIndex index) const { ++ index_bounds_check(index); ++ assert(index != HumongousIndex, "Do not call for humongous chunks."); ++ return _free_chunks[index].size(); ++} ++ + void ChunkManager::locked_verify_free_chunks_total() { + assert_lock_strong(SpaceManager::expand_lock()); + assert(sum_free_chunks() == _free_chunks_total, +@@ -1918,7 +1970,83 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) { + + void ChunkManager::print_on(outputStream* out) const { + if (PrintFLSStatistics != 0) { +- const_cast(this)->humongous_dictionary()->report_statistics(); ++ _humongous_dictionary.report_statistics(); ++ } ++} ++ ++void ChunkManager::locked_get_statistics(ChunkManagerStatistics* stat) const { ++ assert_lock_strong(SpaceManager::expand_lock()); ++ for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { ++ stat->num_by_type[i] = num_free_chunks(i); ++ stat->single_size_by_type[i] = size_by_index(i); ++ stat->total_size_by_type[i] = size_free_chunks_in_bytes(i); ++ } ++ stat->num_humongous_chunks = num_free_chunks(HumongousIndex); ++ stat->total_size_humongous_chunks = size_free_chunks_in_bytes(HumongousIndex); ++} ++ ++void ChunkManager::get_statistics(ChunkManagerStatistics* stat) const { ++ MutexLockerEx cl(SpaceManager::expand_lock(), ++ Mutex::_no_safepoint_check_flag); ++ locked_get_statistics(stat); ++} ++ ++void ChunkManager::print_statistics(const ChunkManagerStatistics* stat, outputStream* out, size_t scale) { ++ size_t total = 0; ++ assert(scale == 1 || scale == K || scale == M || scale == G, "Invalid scale"); ++ ++ const char* unit = scale_unit(scale); ++ for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { ++ out->print(" " SIZE_FORMAT " %s (" SIZE_FORMAT " bytes) chunks, total ", ++ stat->num_by_type[i], chunk_size_name(i), ++ stat->single_size_by_type[i]); ++ if (scale == 1) { ++ out->print_cr(SIZE_FORMAT " bytes", stat->total_size_by_type[i]); ++ } else { ++ out->print_cr("%.2f%s", (float)stat->total_size_by_type[i] / scale, unit); ++ } ++ ++ total += stat->total_size_by_type[i]; ++ } ++ ++ total += stat->total_size_humongous_chunks; ++ ++ if (scale == 1) { ++ out->print_cr(" " SIZE_FORMAT " humongous chunks, total " SIZE_FORMAT " bytes", ++ stat->num_humongous_chunks, stat->total_size_humongous_chunks); ++ ++ out->print_cr(" total size: " SIZE_FORMAT " bytes.", total); ++ } else { ++ out->print_cr(" " SIZE_FORMAT " humongous chunks, total %.2f%s", ++ stat->num_humongous_chunks, ++ (float)stat->total_size_humongous_chunks / scale, unit); ++ ++ out->print_cr(" total size: %.2f%s.", (float)total / scale, unit); ++ } ++ ++} ++ ++void ChunkManager::print_all_chunkmanagers(outputStream* out, size_t scale) { ++ assert(scale == 1 || scale == K || scale == M || scale == G, "Invalid scale"); ++ ++ // Note: keep lock protection only to retrieving statistics; keep printing ++ // out of lock protection ++ ChunkManagerStatistics stat; ++ out->print_cr("Chunkmanager (non-class):"); ++ const ChunkManager* const non_class_cm = Metaspace::chunk_manager_metadata(); ++ if (non_class_cm != NULL) { ++ non_class_cm->get_statistics(&stat); ++ ChunkManager::print_statistics(&stat, out, scale); ++ } else { ++ out->print_cr("unavailable."); ++ } ++ out->print_cr("Chunkmanager (class):"); ++ const ChunkManager* const class_cm = Metaspace::chunk_manager_class(); ++ if (class_cm != NULL) { ++ class_cm->get_statistics(&stat); ++ ChunkManager::print_statistics(&stat, out, scale); ++ } else { ++ out->print_cr("unavailable."); + } + } + +@@ -2930,6 +3058,195 @@ void MetaspaceAux::print_waste(outputStream* out) { + } + } + ++class MetadataStats VALUE_OBJ_CLASS_SPEC { ++private: ++ size_t _capacity; ++ size_t _used; ++ size_t _free; ++ size_t _waste; ++ ++public: ++ MetadataStats() : _capacity(0), _used(0), _free(0), _waste(0) { } ++ MetadataStats(size_t capacity, size_t used, size_t free, size_t waste) ++ : _capacity(capacity), _used(used), _free(free), _waste(waste) { } ++ ++ void add(const MetadataStats& stats) { ++ _capacity += stats.capacity(); ++ _used += stats.used(); ++ _free += stats.free(); ++ _waste += stats.waste(); ++ } ++ ++ size_t capacity() const { return _capacity; } ++ size_t used() const { return _used; } ++ size_t free() const { return _free; } ++ size_t waste() const { return _waste; } ++ ++ void print_on(outputStream* out, size_t scale) const; ++}; ++ ++ ++void MetadataStats::print_on(outputStream* out, size_t scale) const { ++ const char* unit = scale_unit(scale); ++ out->print_cr("capacity=%10.2f%s used=%10.2f%s free=%10.2f%s waste=%10.2f%s", ++ (float)capacity() / scale, unit, ++ (float)used() / scale, unit, ++ (float)free() / scale, unit, ++ (float)waste() / scale, unit); ++} ++ ++class PrintCLDMetaspaceInfoClosure : public CLDClosure { ++private: ++ outputStream* _out; ++ size_t _scale; ++ ++ size_t _total_count; ++ MetadataStats _total_metadata; ++ MetadataStats _total_class; ++ ++ size_t _total_anon_count; ++ MetadataStats _total_anon_metadata; ++ MetadataStats _total_anon_class; ++ ++public: ++ PrintCLDMetaspaceInfoClosure(outputStream* out, size_t scale = K) ++ : _out(out), _scale(scale), _total_count(0), _total_anon_count(0) { } ++ ++ ~PrintCLDMetaspaceInfoClosure() { ++ print_summary(); ++ } ++ ++ void do_cld(ClassLoaderData* cld) { ++ assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint"); ++ ++ if (cld->is_unloading()) return; ++ Metaspace* msp = cld->metaspace_or_null(); ++ if (msp == NULL) { ++ return; ++ } ++ ++ bool anonymous = false; ++ if (cld->is_anonymous()) { ++ _out->print_cr("ClassLoader: for anonymous class"); ++ anonymous = true; ++ } else { ++ ResourceMark rm; ++ _out->print_cr("ClassLoader: %s", cld->loader_name()); ++ } ++ ++ print_metaspace(msp, anonymous); ++ _out->cr(); ++ } ++ ++private: ++ void print_metaspace(Metaspace* msp, bool anonymous); ++ void print_summary() const; ++}; ++ ++void PrintCLDMetaspaceInfoClosure::print_metaspace(Metaspace* msp, bool anonymous){ ++ assert(msp != NULL, "Sanity"); ++ SpaceManager* vsm = msp->vsm(); ++ const char* unit = scale_unit(_scale); ++ ++ size_t capacity = vsm->sum_capacity_in_chunks_in_use() * BytesPerWord; ++ size_t used = vsm->sum_used_in_chunks_in_use() * BytesPerWord; ++ size_t free = vsm->sum_free_in_chunks_in_use() * BytesPerWord; ++ size_t waste = vsm->sum_waste_in_chunks_in_use() * BytesPerWord; ++ ++ _total_count ++; ++ MetadataStats metadata_stats(capacity, used, free, waste); ++ _total_metadata.add(metadata_stats); ++ ++ if (anonymous) { ++ _total_anon_count ++; ++ _total_anon_metadata.add(metadata_stats); ++ } ++ ++ _out->print(" Metadata "); ++ metadata_stats.print_on(_out, _scale); ++ ++ if (Metaspace::using_class_space()) { ++ vsm = msp->class_vsm(); ++ ++ capacity = vsm->sum_capacity_in_chunks_in_use() * BytesPerWord; ++ used = vsm->sum_used_in_chunks_in_use() * BytesPerWord; ++ free = vsm->sum_free_in_chunks_in_use() * BytesPerWord; ++ waste = vsm->sum_waste_in_chunks_in_use() * BytesPerWord; ++ ++ MetadataStats class_stats(capacity, used, free, waste); ++ _total_class.add(class_stats); ++ ++ if (anonymous) { ++ _total_anon_class.add(class_stats); ++ } ++ ++ _out->print(" Class data "); ++ class_stats.print_on(_out, _scale); ++ } ++} ++ ++void PrintCLDMetaspaceInfoClosure::print_summary() const { ++ const char* unit = scale_unit(_scale); ++ _out->cr(); ++ _out->print_cr("Summary:"); ++ ++ MetadataStats total; ++ total.add(_total_metadata); ++ total.add(_total_class); ++ ++ _out->print(" Total class loaders=" SIZE_FORMAT_W(6) " ", _total_count); ++ total.print_on(_out, _scale); ++ ++ _out->print(" Metadata "); ++ _total_metadata.print_on(_out, _scale); ++ ++ if (Metaspace::using_class_space()) { ++ _out->print(" Class data "); ++ _total_class.print_on(_out, _scale); ++ } ++ _out->cr(); ++ ++ MetadataStats total_anon; ++ total_anon.add(_total_anon_metadata); ++ total_anon.add(_total_anon_class); ++ ++ _out->print("For anonymous classes=" SIZE_FORMAT_W(6) " ", _total_anon_count); ++ total_anon.print_on(_out, _scale); ++ ++ _out->print(" Metadata "); ++ _total_anon_metadata.print_on(_out, _scale); ++ ++ if (Metaspace::using_class_space()) { ++ _out->print(" Class data "); ++ _total_anon_class.print_on(_out, _scale); ++ } ++} ++ ++void MetaspaceAux::print_metadata_for_nmt(outputStream* out, size_t scale) { ++ const char* unit = scale_unit(scale); ++ out->print_cr("Metaspaces:"); ++ out->print_cr(" Metadata space: reserved=" SIZE_FORMAT_W(10) "%s committed=" SIZE_FORMAT_W(10) "%s", ++ reserved_bytes(Metaspace::NonClassType) / scale, unit, ++ committed_bytes(Metaspace::NonClassType) / scale, unit); ++ if (Metaspace::using_class_space()) { ++ out->print_cr(" Class space: reserved=" SIZE_FORMAT_W(10) "%s committed=" SIZE_FORMAT_W(10) "%s", ++ reserved_bytes(Metaspace::ClassType) / scale, unit, ++ committed_bytes(Metaspace::ClassType) / scale, unit); ++ } ++ ++ out->cr(); ++ ChunkManager::print_all_chunkmanagers(out, scale); ++ ++ out->cr(); ++ out->print_cr("Per-classloader metadata:"); ++ out->cr(); ++ ++ PrintCLDMetaspaceInfoClosure cl(out, scale); ++ ClassLoaderDataGraph::cld_do(&cl); ++} ++ ++ ++ + // Dump global metaspace things from the end of ClassLoaderDataGraph + void MetaspaceAux::dump(outputStream* out) { + out->print_cr("All Metaspace:"); +@@ -3743,6 +4060,7 @@ void Metaspace::report_metadata_oome(ClassLoaderData* loader_data, size_t word_s + loader_data->dump(gclog_or_tty); + } + MetaspaceAux::dump(gclog_or_tty); ++ ChunkManager::print_all_chunkmanagers(gclog_or_tty); + } + + bool out_of_compressed_class_space = false; +diff --git a/hotspot/src/share/vm/memory/metaspace.hpp b/hotspot/src/share/vm/memory/metaspace.hpp +index 122dd4b..ff1b232 100644 +--- a/hotspot/src/share/vm/memory/metaspace.hpp ++++ b/hotspot/src/share/vm/memory/metaspace.hpp +@@ -65,6 +65,7 @@ class MetaspaceTracer; + class MetaWord; + class Mutex; + class outputStream; ++class PrintCLDMetaspaceInfoClosure; + class SpaceManager; + class VirtualSpaceList; + +@@ -88,6 +89,7 @@ class Metaspace : public CHeapObj { + friend class VM_CollectForMetadataAllocation; + friend class MetaspaceGC; + friend class MetaspaceAux; ++ friend class PrintCLDMetaspaceInfoClosure; + + public: + enum MetadataType { +@@ -372,6 +374,8 @@ class MetaspaceAux : AllStatic { + return min_chunk_size_words() * BytesPerWord; + } + ++ static void print_metadata_for_nmt(outputStream* out, size_t scale = K); ++ + static bool has_chunk_free_list(Metaspace::MetadataType mdtype); + static MetaspaceChunkFreeListSummary chunk_free_list_summary(Metaspace::MetadataType mdtype); + +diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp +index d401ea6..b42d18f 100644 +--- a/hotspot/src/share/vm/runtime/vm_operations.cpp ++++ b/hotspot/src/share/vm/runtime/vm_operations.cpp +@@ -209,6 +209,10 @@ void VM_PrintJNI::doit() { + JNIHandles::print_on(_out); + } + ++void VM_PrintMetadata::doit() { ++ MetaspaceAux::print_metadata_for_nmt(_out, _scale); ++} ++ + VM_FindDeadlocks::~VM_FindDeadlocks() { + if (_deadlocks != NULL) { + DeadlockCycle* cycle = _deadlocks; +diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp +index 3744040..19c33f8 100644 +--- a/hotspot/src/share/vm/runtime/vm_operations.hpp ++++ b/hotspot/src/share/vm/runtime/vm_operations.hpp +@@ -101,6 +101,7 @@ + template(ClassLoaderHierarchyOperation) \ + template(JFROldObject) \ + template(PrintClasses) \ ++ template(PrintMetadata) \ + + class VM_Operation: public CHeapObj { + public: +@@ -329,6 +330,17 @@ class VM_PrintJNI: public VM_Operation { + void doit(); + }; + ++class VM_PrintMetadata : public VM_Operation { ++ private: ++ outputStream* _out; ++ size_t _scale; ++ public: ++ VM_PrintMetadata(outputStream* out, size_t scale) : _out(out), _scale(scale) {}; ++ ++ VMOp_Type type() const { return VMOp_PrintMetadata; } ++ void doit(); ++}; ++ + class DeadlockCycle; + class VM_FindDeadlocks: public VM_Operation { + private: +diff --git a/hotspot/src/share/vm/services/nmtDCmd.cpp b/hotspot/src/share/vm/services/nmtDCmd.cpp +index fcad784..659ca33 100644 +--- a/hotspot/src/share/vm/services/nmtDCmd.cpp ++++ b/hotspot/src/share/vm/services/nmtDCmd.cpp +@@ -24,6 +24,8 @@ + #include "precompiled.hpp" + + #include "runtime/mutexLocker.hpp" ++#include "runtime/vmThread.hpp" ++#include "runtime/vm_operations.hpp" + #include "services/nmtDCmd.hpp" + #include "services/memReporter.hpp" + #include "services/memTracker.hpp" +@@ -38,6 +40,8 @@ NMTDCmd::NMTDCmd(outputStream* output, + _detail("detail", "request runtime to report memory allocation >= " + "1K by each callsite.", + "BOOLEAN", false, "false"), ++ _metadata("metadata", "request runtime to report metadata information", ++ "BOOLEAN", false, "false"), + _baseline("baseline", "request runtime to baseline current memory usage, " \ + "so it can be compared against in later time.", + "BOOLEAN", false, "false"), +@@ -57,6 +61,7 @@ NMTDCmd::NMTDCmd(outputStream* output, + "STRING", false, "KB") { + _dcmdparser.add_dcmd_option(&_summary); + _dcmdparser.add_dcmd_option(&_detail); ++ _dcmdparser.add_dcmd_option(&_metadata); + _dcmdparser.add_dcmd_option(&_baseline); + _dcmdparser.add_dcmd_option(&_summary_diff); + _dcmdparser.add_dcmd_option(&_detail_diff); +@@ -92,6 +97,7 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { + int nopt = 0; + if (_summary.is_set() && _summary.value()) { ++nopt; } + if (_detail.is_set() && _detail.value()) { ++nopt; } ++ if (_metadata.is_set() && _metadata.value()) { ++nopt; } + if (_baseline.is_set() && _baseline.value()) { ++nopt; } + if (_summary_diff.is_set() && _summary_diff.value()) { ++nopt; } + if (_detail_diff.is_set() && _detail_diff.value()) { ++nopt; } +@@ -100,7 +106,7 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { + + if (nopt > 1) { + output()->print_cr("At most one of the following option can be specified: " \ +- "summary, detail, baseline, summary.diff, detail.diff, shutdown"); ++ "summary, detail, metadata, baseline, summary.diff, detail.diff, shutdown"); + return; + } else if (nopt == 0) { + if (_summary.is_set()) { +@@ -118,9 +124,13 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { + report(true, scale_unit); + } else if (_detail.value()) { + if (!check_detail_tracking_level(output())) { +- return; +- } ++ return; ++ } + report(false, scale_unit); ++ } else if (_metadata.value()) { ++ size_t scale = get_scale(_scale.value()); ++ VM_PrintMetadata op(output(), scale); ++ VMThread::execute(&op); + } else if (_baseline.value()) { + MemBaseline& baseline = MemTracker::get_baseline(); + if (!baseline.baseline(MemTracker::tracking_level() != NMT_detail)) { +diff --git a/hotspot/src/share/vm/services/nmtDCmd.hpp b/hotspot/src/share/vm/services/nmtDCmd.hpp +index df1ab36..bbd1391 100644 +--- a/hotspot/src/share/vm/services/nmtDCmd.hpp ++++ b/hotspot/src/share/vm/services/nmtDCmd.hpp +@@ -39,6 +39,7 @@ class NMTDCmd: public DCmdWithParser { + protected: + DCmdArgument _summary; + DCmdArgument _detail; ++ DCmdArgument _metadata; + DCmdArgument _baseline; + DCmdArgument _summary_diff; + DCmdArgument _detail_diff; +-- +1.8.3.1 diff --git a/8198553-jcmd-separate-Metaspace-statistics-from-NMT.patch b/8198553-jcmd-separate-Metaspace-statistics-from-NMT.patch new file mode 100644 index 0000000..d2b5208 --- /dev/null +++ b/8198553-jcmd-separate-Metaspace-statistics-from-NMT.patch @@ -0,0 +1,165 @@ +From d19efeaa550f4a2069273d9ab23c27a53bf4ec91 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Thu, 15 Dec 2022 19:00:53 +0800 +Subject: [PATCH 22/33] I68TO2: 8198553: jcmd: separate Metaspace statistics from NMT +--- + .../src/share/vm/services/diagnosticCommand.cpp | 1 + + .../src/share/vm/services/diagnosticCommand.hpp | 23 +++++++++++++- + hotspot/src/share/vm/services/metaspaceDCmd.cpp | 36 ++++++++++++++++++++++ + hotspot/src/share/vm/services/nmtDCmd.cpp | 10 +----- + hotspot/src/share/vm/services/nmtDCmd.hpp | 1 - + 5 files changed, 60 insertions(+), 11 deletions(-) + create mode 100644 hotspot/src/share/vm/services/metaspaceDCmd.cpp + +diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp +index d3b91d9..c9bc7d2 100644 +--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp ++++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp +@@ -67,6 +67,7 @@ void DCmdRegistrant::register_dcmds(){ + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); ++ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + #endif // INCLUDE_SERVICES + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); +diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp +index f86ab5f..275e053 100644 +--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp ++++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -487,4 +487,25 @@ public: + } + }; + ++class MetaspaceDCmd : public DCmd { ++public: ++ MetaspaceDCmd(outputStream* output, bool heap); ++ static const char* name() { ++ return "VM.metaspace"; ++ } ++ static const char* description() { ++ return "Prints the statistics for the metaspace"; ++ } ++ static const char* impact() { ++ return "Medium: Depends on number of classes loaded."; ++ } ++ static const JavaPermission permission() { ++ JavaPermission p = {"java.lang.management.ManagementPermission", ++ "monitor", NULL}; ++ return p; ++ } ++ static int num_arguments() { return 0; } ++ virtual void execute(DCmdSource source, TRAPS); ++}; ++ + #endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP +diff --git a/hotspot/src/share/vm/services/metaspaceDCmd.cpp b/hotspot/src/share/vm/services/metaspaceDCmd.cpp +new file mode 100644 +index 0000000..9d4262e +--- /dev/null ++++ b/hotspot/src/share/vm/services/metaspaceDCmd.cpp +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++#include "precompiled.hpp" ++#include "memory/metaspace.hpp" ++#include "services/diagnosticCommand.hpp" ++ ++MetaspaceDCmd::MetaspaceDCmd(outputStream* output, bool heap): DCmd(output, heap) { ++} ++ ++void MetaspaceDCmd::execute(DCmdSource source, TRAPS) { ++ const size_t scale = 1 * K; ++ VM_PrintMetadata op(output(), scale); ++ VMThread::execute(&op); ++} +diff --git a/hotspot/src/share/vm/services/nmtDCmd.cpp b/hotspot/src/share/vm/services/nmtDCmd.cpp +index 659ca33..2635bbb 100644 +--- a/hotspot/src/share/vm/services/nmtDCmd.cpp ++++ b/hotspot/src/share/vm/services/nmtDCmd.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -40,8 +40,6 @@ NMTDCmd::NMTDCmd(outputStream* output, + _detail("detail", "request runtime to report memory allocation >= " + "1K by each callsite.", + "BOOLEAN", false, "false"), +- _metadata("metadata", "request runtime to report metadata information", +- "BOOLEAN", false, "false"), + _baseline("baseline", "request runtime to baseline current memory usage, " \ + "so it can be compared against in later time.", + "BOOLEAN", false, "false"), +@@ -61,7 +59,6 @@ NMTDCmd::NMTDCmd(outputStream* output, + "STRING", false, "KB") { + _dcmdparser.add_dcmd_option(&_summary); + _dcmdparser.add_dcmd_option(&_detail); +- _dcmdparser.add_dcmd_option(&_metadata); + _dcmdparser.add_dcmd_option(&_baseline); + _dcmdparser.add_dcmd_option(&_summary_diff); + _dcmdparser.add_dcmd_option(&_detail_diff); +@@ -97,7 +94,6 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { + int nopt = 0; + if (_summary.is_set() && _summary.value()) { ++nopt; } + if (_detail.is_set() && _detail.value()) { ++nopt; } +- if (_metadata.is_set() && _metadata.value()) { ++nopt; } + if (_baseline.is_set() && _baseline.value()) { ++nopt; } + if (_summary_diff.is_set() && _summary_diff.value()) { ++nopt; } + if (_detail_diff.is_set() && _detail_diff.value()) { ++nopt; } +@@ -127,10 +123,6 @@ void NMTDCmd::execute(DCmdSource source, TRAPS) { + return; + } + report(false, scale_unit); +- } else if (_metadata.value()) { +- size_t scale = get_scale(_scale.value()); +- VM_PrintMetadata op(output(), scale); +- VMThread::execute(&op); + } else if (_baseline.value()) { + MemBaseline& baseline = MemTracker::get_baseline(); + if (!baseline.baseline(MemTracker::tracking_level() != NMT_detail)) { +diff --git a/hotspot/src/share/vm/services/nmtDCmd.hpp b/hotspot/src/share/vm/services/nmtDCmd.hpp +index bbd1391..df1ab36 100644 +--- a/hotspot/src/share/vm/services/nmtDCmd.hpp ++++ b/hotspot/src/share/vm/services/nmtDCmd.hpp +@@ -39,7 +39,6 @@ class NMTDCmd: public DCmdWithParser { + protected: + DCmdArgument _summary; + DCmdArgument _detail; +- DCmdArgument _metadata; + DCmdArgument _baseline; + DCmdArgument _summary_diff; + DCmdArgument _detail_diff; +-- +1.8.3.1 diff --git a/8200720-Print-additional-information-in-thread-dump-.patch b/8200720-Print-additional-information-in-thread-dump-.patch new file mode 100644 index 0000000..12c1b59 --- /dev/null +++ b/8200720-Print-additional-information-in-thread-dump-.patch @@ -0,0 +1,409 @@ +From f68539b01f6345809266cf57fe4bdc0f45c8ab37 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Fri, 16 Dec 2022 10:02:37 +0800 +Subject: [PATCH 25/33] I68TO2: 8200720: Print additional information in thread dump + (times, allocated bytes etc.) +--- + hotspot/src/share/vm/classfile/classFileParser.cpp | 4 ++ + hotspot/src/share/vm/runtime/globals.hpp | 3 ++ + hotspot/src/share/vm/runtime/thread.cpp | 29 ++++++++++--- + hotspot/src/share/vm/runtime/thread.hpp | 15 +++++-- + .../src/share/vm/runtime/threadStatisticalInfo.hpp | 49 ++++++++++++++++++++++ + hotspot/src/share/vm/runtime/vm_operations.cpp | 2 +- + hotspot/src/share/vm/runtime/vm_operations.hpp | 13 ++++-- + hotspot/src/share/vm/services/attachListener.cpp | 14 +++++-- + .../src/share/vm/services/diagnosticCommand.cpp | 6 ++- + .../src/share/vm/services/diagnosticCommand.hpp | 1 + + jdk/src/share/classes/sun/tools/jstack/JStack.java | 19 ++++++--- + 11 files changed, 131 insertions(+), 24 deletions(-) + create mode 100644 hotspot/src/share/vm/runtime/threadStatisticalInfo.hpp + +diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp +index 3ec6aec..51ab4f5 100644 +--- a/hotspot/src/share/vm/classfile/classFileParser.cpp ++++ b/hotspot/src/share/vm/classfile/classFileParser.cpp +@@ -3843,6 +3843,10 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, + ClassFileStream* cfs = stream(); + // Timing + assert(THREAD->is_Java_thread(), "must be a JavaThread"); ++ ++ // increment counter ++ THREAD->statistical_info().incr_define_class_count(); ++ + JavaThread* jt = (JavaThread*) THREAD; + + PerfClassTraceTime ctimer(ClassLoader::perf_class_parse_time(), +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 14c3c89..2631971 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -1001,6 +1001,9 @@ class CommandLineFlags { + product(bool, PrintCompilation, false, \ + "Print compilations") \ + \ ++ product(bool, PrintExtendedThreadInfo, false, \ ++ "Print more information in thread dump") \ ++ \ + diagnostic(bool, TraceNMethodInstalls, false, \ + "Trace nmethod installation") \ + \ +diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp +index 61627e4..bd35e95 100644 +--- a/hotspot/src/share/vm/runtime/thread.cpp ++++ b/hotspot/src/share/vm/runtime/thread.cpp +@@ -71,6 +71,7 @@ + #include "runtime/thread.inline.hpp" + #include "runtime/threadCritical.hpp" + #include "runtime/threadLocalStorage.hpp" ++#include "runtime/threadStatisticalInfo.hpp" + #include "runtime/vframe.hpp" + #include "runtime/vframeArray.hpp" + #include "runtime/vframe_hp.hpp" +@@ -859,13 +860,29 @@ void Thread::metadata_do(void f(Metadata*)) { + } + } + +-void Thread::print_on(outputStream* st) const { ++void Thread::print_on(outputStream* st, bool print_extended_info) const { + // get_priority assumes osthread initialized + if (osthread() != NULL) { + int os_prio; + if (os::get_native_priority(this, &os_prio) == OS_OK) { + st->print("os_prio=%d ", os_prio); + } ++ ++ st->print("cpu=%.2fms ", ++ os::thread_cpu_time(const_cast(this), true) / 1000000.0 ++ ); ++ st->print("elapsed=%.2fs ", ++ _statistical_info.getElapsedTime() / 1000.0 ++ ); ++ if (is_Java_thread() && (PrintExtendedThreadInfo || print_extended_info)) { ++ size_t allocated_bytes = (size_t) const_cast(this)->cooked_allocated_bytes(); ++ st->print("allocated=" SIZE_FORMAT "%s ", ++ byte_size_in_proper_unit(allocated_bytes), ++ proper_unit_for_byte_size(allocated_bytes) ++ ); ++ st->print("defined_classes=" INT64_FORMAT " ", _statistical_info.getDefineClassCount()); ++ } ++ + st->print("tid=" INTPTR_FORMAT " ", this); + ext().print_on(st); + osthread()->print_on(st); +@@ -2856,7 +2873,7 @@ void JavaThread::print_thread_state() const { + #endif // PRODUCT + + // Called by Threads::print() for VM_PrintThreads operation +-void JavaThread::print_on(outputStream *st) const { ++void JavaThread::print_on(outputStream *st, bool print_extended_info) const { + st->print("\"%s\" ", get_thread_name()); + oop thread_oop = threadObj(); + if (thread_oop != NULL) { +@@ -2864,7 +2881,7 @@ void JavaThread::print_on(outputStream *st) const { + if (java_lang_Thread::is_daemon(thread_oop)) st->print("daemon "); + st->print("prio=%d ", java_lang_Thread::priority(thread_oop)); + } +- Thread::print_on(st); ++ Thread::print_on(st, print_extended_info); + // print guess for valid stack memory region (assume 4K pages); helps lock debugging + st->print_cr("[" INTPTR_FORMAT "]", (intptr_t)last_Java_sp() & ~right_n_bits(12)); + if (thread_oop != NULL && JDK_Version::is_gte_jdk15x_version()) { +@@ -4344,7 +4361,9 @@ JavaThread *Threads::owning_thread_from_monitor_owner(address owner, bool doLock + } + + // Threads::print_on() is called at safepoint by VM_PrintThreads operation. +-void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format, bool print_concurrent_locks) { ++void Threads::print_on(outputStream* st, bool print_stacks, ++ bool internal_format, bool print_concurrent_locks, ++ bool print_extended_info) { + char buf[32]; + st->print_cr("%s", os::local_time_string(buf, sizeof(buf))); + +@@ -4365,7 +4384,7 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format + + ALL_JAVA_THREADS(p) { + ResourceMark rm; +- p->print_on(st); ++ p->print_on(st, print_extended_info); + if (print_stacks) { + if (internal_format) { + p->trace_stack(); +diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp +index fcd4814..be53498 100644 +--- a/hotspot/src/share/vm/runtime/thread.hpp ++++ b/hotspot/src/share/vm/runtime/thread.hpp +@@ -41,6 +41,7 @@ + #include "runtime/stubRoutines.hpp" + #include "runtime/threadLocalStorage.hpp" + #include "runtime/thread_ext.hpp" ++#include "runtime/threadStatisticalInfo.hpp" + #include "runtime/unhandledOops.hpp" + #include "utilities/exceptions.hpp" + #include "utilities/macros.hpp" +@@ -263,6 +264,8 @@ class Thread: public ThreadShadow { + // Thread-local buffer used by MetadataOnStackMark. + MetadataOnStackBuffer* _metadata_on_stack_buffer; + ++ ThreadStatisticalInfo _statistical_info; // Statistics about the thread ++ + JFR_ONLY(DEFINE_THREAD_LOCAL_FIELD_JFR;) // Thread-local data for jfr + + ThreadExt _ext; +@@ -446,6 +449,8 @@ class Thread: public ThreadShadow { + void incr_allocated_bytes(jlong size) { _allocated_bytes += size; } + inline jlong cooked_allocated_bytes(); + ++ ThreadStatisticalInfo& statistical_info() { return _statistical_info; } ++ + JFR_ONLY(DEFINE_THREAD_LOCAL_ACCESSOR_JFR;) + JFR_ONLY(DEFINE_TRACE_SUSPEND_FLAG_METHODS) + +@@ -570,7 +575,8 @@ protected: + void set_lgrp_id(int value) { _lgrp_id = value; } + + // Printing +- void print_on(outputStream* st) const; ++ void print_on(outputStream* st, bool print_extended_info) const; ++ void print_on(outputStream* st) const { print_on(st, false); } + void print() const { print_on(tty); } + virtual void print_on_error(outputStream* st, char* buf, int buflen) const; + +@@ -1463,7 +1469,8 @@ class JavaThread: public Thread { + + // Misc. operations + char* name() const { return (char*)get_thread_name(); } +- void print_on(outputStream* st) const; ++ void print_on(outputStream* st, bool print_extended_info) const; ++ void print_on(outputStream* st) const { print_on(st, false); } + void print() const { print_on(tty); } + void print_value(); + void print_thread_state_on(outputStream* ) const PRODUCT_RETURN; +@@ -1975,10 +1982,10 @@ class Threads: AllStatic { + + // Verification + static void verify(); +- static void print_on(outputStream* st, bool print_stacks, bool internal_format, bool print_concurrent_locks); ++ static void print_on(outputStream* st, bool print_stacks, bool internal_format, bool print_concurrent_locks, bool print_extended_info); + static void print(bool print_stacks, bool internal_format) { + // this function is only used by debug.cpp +- print_on(tty, print_stacks, internal_format, false /* no concurrent lock printed */); ++ print_on(tty, print_stacks, internal_format, false /* no concurrent lock printed */, false /* simple format */); + } + static void print_on_error(outputStream* st, Thread* current, char* buf, int buflen); + +diff --git a/hotspot/src/share/vm/runtime/threadStatisticalInfo.hpp b/hotspot/src/share/vm/runtime/threadStatisticalInfo.hpp +new file mode 100644 +index 0000000..9dbe62d +--- /dev/null ++++ b/hotspot/src/share/vm/runtime/threadStatisticalInfo.hpp +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018 SAP SE. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * 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 SHARE_VM_RUNTIME_THREADSTATISTICS_HPP ++#define SHARE_VM_RUNTIME_THREADSTATISTICS_HPP ++ ++#include "prims/jni.h" ++#include "runtime/os.hpp" ++#include "utilities/globalDefinitions.hpp" ++ ++ ++class ThreadStatisticalInfo { ++ // The time stamp the thread was started. ++ const uint64_t _start_time_stamp; ++ uint64_t _define_class_count; ++ ++public: ++ ThreadStatisticalInfo() : _start_time_stamp(os::javaTimeMillis()), _define_class_count(0) {} ++ uint64_t getStartTime() const { return _start_time_stamp; } ++ uint64_t getDefineClassCount() const { return _define_class_count; } ++ void setDefineClassCount(uint64_t defineClassCount) { _define_class_count = defineClassCount; } ++ void incr_define_class_count() { _define_class_count += 1; } ++ uint64_t getElapsedTime() const { return os::javaTimeMillis() - getStartTime(); } ++}; ++ ++#endif // SHARE_VM_RUNTIME_THREADSTATISTICS_HPP +diff --git a/hotspot/src/share/vm/runtime/vm_operations.cpp b/hotspot/src/share/vm/runtime/vm_operations.cpp +index b42d18f..03c4249 100644 +--- a/hotspot/src/share/vm/runtime/vm_operations.cpp ++++ b/hotspot/src/share/vm/runtime/vm_operations.cpp +@@ -195,7 +195,7 @@ bool VM_PrintThreads::doit_prologue() { + } + + void VM_PrintThreads::doit() { +- Threads::print_on(_out, true, false, _print_concurrent_locks); ++ Threads::print_on(_out, true, false, _print_concurrent_locks, _print_extended_info); + } + + void VM_PrintThreads::doit_epilogue() { +diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp +index 19c33f8..baf6042 100644 +--- a/hotspot/src/share/vm/runtime/vm_operations.hpp ++++ b/hotspot/src/share/vm/runtime/vm_operations.hpp +@@ -311,10 +311,17 @@ class VM_PrintThreads: public VM_Operation { + private: + outputStream* _out; + bool _print_concurrent_locks; ++ bool _print_extended_info; + public: +- VM_PrintThreads() { _out = tty; _print_concurrent_locks = PrintConcurrentLocks; } +- VM_PrintThreads(outputStream* out, bool print_concurrent_locks) { _out = out; _print_concurrent_locks = print_concurrent_locks; } +- VMOp_Type type() const { return VMOp_PrintThreads; } ++ VM_PrintThreads() ++ : _out(tty), _print_concurrent_locks(PrintConcurrentLocks), _print_extended_info(false) ++ {} ++ VM_PrintThreads(outputStream* out, bool print_concurrent_locks, bool print_extended_info) ++ : _out(out), _print_concurrent_locks(print_concurrent_locks), _print_extended_info(print_extended_info) ++ {} ++ VMOp_Type type() const { ++ return VMOp_PrintThreads; ++ } + void doit(); + bool doit_prologue(); + void doit_epilogue(); +diff --git a/hotspot/src/share/vm/services/attachListener.cpp b/hotspot/src/share/vm/services/attachListener.cpp +index d4dea71..7c57637 100644 +--- a/hotspot/src/share/vm/services/attachListener.cpp ++++ b/hotspot/src/share/vm/services/attachListener.cpp +@@ -132,12 +132,20 @@ static jint data_dump(AttachOperation* op, outputStream* out) { + // + static jint thread_dump(AttachOperation* op, outputStream* out) { + bool print_concurrent_locks = false; +- if (op->arg(0) != NULL && strcmp(op->arg(0), "-l") == 0) { +- print_concurrent_locks = true; ++ bool print_extended_info = false; ++ if (op->arg(0) != NULL) { ++ for (int i = 0; op->arg(0)[i] != 0; ++i) { ++ if (op->arg(0)[i] == 'l') { ++ print_concurrent_locks = true; ++ } ++ if (op->arg(0)[i] == 'e') { ++ print_extended_info = true; ++ } ++ } + } + + // thread stacks +- VM_PrintThreads op1(out, print_concurrent_locks); ++ VM_PrintThreads op1(out, print_concurrent_locks, print_extended_info); + VMThread::execute(&op1); + + // JNI global handles +diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp +index c9bc7d2..fb8e293 100644 +--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp ++++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp +@@ -535,13 +535,15 @@ int ClassStatsDCmd::num_arguments() { + + ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), +- _locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false") { ++ _locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false"), ++ _extended("-e", "print extended thread information", "BOOLEAN", false, "false") { + _dcmdparser.add_dcmd_option(&_locks); ++ _dcmdparser.add_dcmd_option(&_extended); + } + + void ThreadDumpDCmd::execute(DCmdSource source, TRAPS) { + // thread stacks +- VM_PrintThreads op1(output(), _locks.value()); ++ VM_PrintThreads op1(output(), _locks.value(), _extended.value()); + VMThread::execute(&op1); + + // JNI global handles +diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp +index 275e053..87bff52 100644 +--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp ++++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp +@@ -362,6 +362,7 @@ public: + class ThreadDumpDCmd : public DCmdWithParser { + protected: + DCmdArgument _locks; ++ DCmdArgument _extended; + public: + ThreadDumpDCmd(outputStream* output, bool heap); + static const char* name() { return "Thread.print"; } +diff --git a/jdk/src/share/classes/sun/tools/jstack/JStack.java b/jdk/src/share/classes/sun/tools/jstack/JStack.java +index 6c96af2..3eea094 100644 +--- a/jdk/src/share/classes/sun/tools/jstack/JStack.java ++++ b/jdk/src/share/classes/sun/tools/jstack/JStack.java +@@ -48,6 +48,7 @@ public class JStack { + boolean useSA = false; + boolean mixed = false; + boolean locks = false; ++ boolean extended = false; + + // Parse the options (arguments starting with "-" ) + int optionCount = 0; +@@ -69,7 +70,11 @@ public class JStack { + if (arg.equals("-l")) { + locks = true; + } else { +- usage(1); ++ if (arg.equals("-e")) { ++ extended = true; ++ } else { ++ usage(1); ++ } + } + } + } +@@ -107,11 +112,12 @@ public class JStack { + } else { + // pass -l to thread dump operation to get extra lock info + String pid = args[optionCount]; +- String params[]; ++ String params[]= new String[] { "" }; ++ if (extended) { ++ params[0] += "-e "; ++ } + if (locks) { +- params = new String[] { "-l" }; +- } else { +- params = new String[0]; ++ params[0] += "-l"; + } + runThreadDump(pid, params); + } +@@ -205,7 +211,7 @@ public class JStack { + // print usage message + private static void usage(int exit) { + System.err.println("Usage:"); +- System.err.println(" jstack [-l] "); ++ System.err.println(" jstack [-l][-e] "); + System.err.println(" (to connect to running process)"); + + if (loadSAClass() != null) { +@@ -227,6 +233,7 @@ public class JStack { + } + + System.err.println(" -l long listing. Prints additional information about locks"); ++ System.err.println(" -e extended listing. Prints additional information about threads"); + System.err.println(" -h or -help to print this help message"); + System.exit(exit); + } +-- +1.8.3.1 diff --git a/8203682-Add-jcmd-VM.classloaders-command-to-print-ou.patch b/8203682-Add-jcmd-VM.classloaders-command-to-print-ou.patch new file mode 100644 index 0000000..d8778fa --- /dev/null +++ b/8203682-Add-jcmd-VM.classloaders-command-to-print-ou.patch @@ -0,0 +1,811 @@ +From 953fdbbfbc6512c3f04f3663fa5ad216d7547984 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Thu, 15 Dec 2022 09:48:37 +0800 +Subject: [PATCH 17/33] I68TO2: 8203682: Add jcmd "VM.classloaders" command to print + out class loader hierarchy, details +--- + .../vm/classfile/classLoaderHierarchyDCmd.cpp | 468 +++++++++++++++++++++ + .../vm/classfile/classLoaderHierarchyDCmd.hpp | 59 +++ + hotspot/src/share/vm/runtime/vm_operations.hpp | 1 + + .../src/share/vm/services/diagnosticCommand.cpp | 2 + + .../dcmd/ClassLoaderHierarchyTest.java | 213 ++++++++++ + 5 files changed, 743 insertions(+) + create mode 100644 hotspot/src/share/vm/classfile/classLoaderHierarchyDCmd.cpp + create mode 100644 hotspot/src/share/vm/classfile/classLoaderHierarchyDCmd.hpp + create mode 100644 hotspot/test/serviceability/dcmd/ClassLoaderHierarchyTest.java + +diff --git a/hotspot/src/share/vm/classfile/classLoaderHierarchyDCmd.cpp b/hotspot/src/share/vm/classfile/classLoaderHierarchyDCmd.cpp +new file mode 100644 +index 0000000..4c25091 +--- /dev/null ++++ b/hotspot/src/share/vm/classfile/classLoaderHierarchyDCmd.cpp +@@ -0,0 +1,468 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018 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 ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++ ++#include "classfile/classLoaderData.inline.hpp" ++#include "classfile/classLoaderHierarchyDCmd.hpp" ++#include "memory/allocation.hpp" ++#include "memory/resourceArea.hpp" ++#include "runtime/safepoint.hpp" ++#include "utilities/globalDefinitions.hpp" ++#include "utilities/ostream.hpp" ++ ++ ++ClassLoaderHierarchyDCmd::ClassLoaderHierarchyDCmd(outputStream* output, bool heap) ++ : DCmdWithParser(output, heap) ++ , _show_classes("show-classes", "Print loaded classes.", "BOOLEAN", false, "false") ++ , _verbose("verbose", "Print detailed information.", "BOOLEAN", false, "false") { ++ _dcmdparser.add_dcmd_option(&_show_classes); ++ _dcmdparser.add_dcmd_option(&_verbose); ++} ++ ++ ++int ClassLoaderHierarchyDCmd::num_arguments() { ++ ResourceMark rm; ++ ClassLoaderHierarchyDCmd* dcmd = new ClassLoaderHierarchyDCmd(NULL, false); ++ if (dcmd != NULL) { ++ DCmdMark mark(dcmd); ++ return dcmd->_dcmdparser.num_arguments(); ++ } else { ++ return 0; ++ } ++} ++ ++// Helper class for drawing the branches to the left of a node. ++class BranchTracker : public StackObj { ++ // "" ++ // " |---" ++ // " | | ++ // " | " ++ // " | |--- ++ // " | |--- ++ // ^^^^^^^ ^^^ ++ // A B ++ ++ // Some terms for the graphics: ++ // - branch: vertical connection between a node's ancestor to a later sibling. ++ // - branchwork: (A) the string to print as a prefix at the start of each line, contains all branches. ++ // - twig (B): Length of the dashed line connecting a node to its branch. ++ // - branch spacing: how many spaces between branches are printed. ++ ++public: ++ ++ enum { max_depth = 64, twig_len = 2, branch_spacing = 5 }; ++ ++private: ++ ++ char _branches[max_depth]; ++ int _pos; ++ ++public: ++ BranchTracker() ++ : _pos(0) {} ++ ++ void push(bool has_branch) { ++ if (_pos < max_depth) { ++ _branches[_pos] = has_branch ? '|' : ' '; ++ } ++ _pos ++; // beyond max depth, omit branch drawing but do count on. ++ } ++ ++ void pop() { ++ assert(_pos > 0, "must be"); ++ _pos --; ++ } ++ ++ void print(outputStream* st) { ++ for (int i = 0; i < _pos; i ++) { ++ st->print("%c%.*s", _branches[i], branch_spacing, " "); ++ } ++ } ++ ++ class Mark { ++ BranchTracker& _tr; ++ public: ++ Mark(BranchTracker& tr, bool has_branch_here) ++ : _tr(tr) { _tr.push(has_branch_here); } ++ ~Mark() { _tr.pop(); } ++ }; ++ ++}; // end: BranchTracker ++ ++struct LoadedClassInfo : public ResourceObj { ++public: ++ LoadedClassInfo* _next; ++ Klass* const _klass; ++ const ClassLoaderData* const _cld; ++ ++ LoadedClassInfo(Klass* klass, const ClassLoaderData* cld) ++ : _next(NULL), _klass(klass), _cld(cld) {} ++ ++}; ++ ++class LoaderTreeNode : public ResourceObj { ++ ++ // We walk the CLDG and, for each CLD which is non-anonymous, add ++ // a tree node. To add a node we need its parent node; if it itself ++ // does not exist yet, we add a preliminary node for it. This preliminary ++ // node just contains its loader oop; later, when encountering its CLD in ++ // our CLDG walk, we complete the missing information in this node. ++ ++ const oop _loader_oop; ++ const ClassLoaderData* _cld; // May be NULL if loader never loaded anything ++ ++ LoaderTreeNode* _child; ++ LoaderTreeNode* _next; ++ ++ LoadedClassInfo* _classes; ++ int _num_classes; ++ ++ LoadedClassInfo* _anon_classes; ++ int _num_anon_classes; ++ ++ // Returns Klass of loader; NULL for bootstrap loader ++ const Klass* loader_klass() const { ++ return (_loader_oop != NULL) ? _loader_oop->klass() : NULL; ++ } ++ ++ // Returns ResourceArea-allocated class name of loader class; "" if there is no klass (bootstrap loader) ++ const char* loader_class_name() const { ++ const Klass* klass = loader_klass(); ++ return klass != NULL ? klass->external_name() : ""; ++ } ++ ++ bool is_bootstrap() const { ++ if (_loader_oop == NULL) { ++ assert(_cld != NULL && _cld->is_the_null_class_loader_data(), "bootstrap loader must have CLD"); ++ return true; ++ } ++ return false; ++ } ++ ++ void print_with_child_nodes(outputStream* st, BranchTracker& branchtracker, ++ bool print_classes, bool verbose) const { ++ ++ assert(SafepointSynchronize::is_at_safepoint(), "invariant"); ++ ++ ResourceMark rm; ++ ++ // Retrieve information. ++ const Klass* const the_loader_klass = loader_klass(); ++ const char* const the_loader_class_name = loader_class_name(); ++ // ClassLoader.java does not contain 'name' field. Replace it with loader_class_name(). ++ const char* const the_loader_name = the_loader_class_name; ++ ++ branchtracker.print(st); ++ ++ // e.g. "+--- jdk.internal.reflect.DelegatingClassLoader" ++ st->print("+%.*s", BranchTracker::twig_len, "----------"); ++ if (is_bootstrap()) { ++ st->print(" "); ++ } else { ++ if (the_loader_name[0] != '\0') { ++ st->print(" \"%s\",", the_loader_name); ++ } ++ st->print(" %s", the_loader_class_name); ++ st->print(" {" PTR_FORMAT "}", p2i(_loader_oop)); ++ } ++ st->cr(); ++ ++ // Output following this node (node details and child nodes) - up to the next sibling node ++ // needs to be prefixed with "|" if there is a follow up sibling. ++ const bool have_sibling = _next != NULL; ++ BranchTracker::Mark trm(branchtracker, have_sibling); ++ ++ { ++ // optional node details following this node needs to be prefixed with "|" ++ // if there are follow up child nodes. ++ const bool have_child = _child != NULL; ++ BranchTracker::Mark trm(branchtracker, have_child); ++ ++ // Empty line ++ branchtracker.print(st); ++ st->cr(); ++ ++ const int indentation = 18; ++ ++ if (verbose) { ++ branchtracker.print(st); ++ st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Data:", p2i(_cld)); ++ branchtracker.print(st); ++ st->print_cr("%*s " PTR_FORMAT, indentation, "Loader Klass:", p2i(the_loader_klass)); ++ ++ // Empty line ++ branchtracker.print(st); ++ st->cr(); ++ } ++ ++ if (print_classes) { ++ ++ if (_classes != NULL) { ++ assert(_cld != NULL, "we have classes, we should have a CLD"); ++ for (LoadedClassInfo* lci = _classes; lci; lci = lci->_next) { ++ branchtracker.print(st); ++ if (lci == _classes) { // first iteration ++ st->print("%*s ", indentation, "Classes:"); ++ } else { ++ st->print("%*s ", indentation, ""); ++ } ++ st->print("%s", lci->_klass->external_name()); ++ st->cr(); ++ // Non-anonymous classes should live in the primary CLD of its loader ++ assert(lci->_cld == _cld, "must be"); ++ } ++ branchtracker.print(st); ++ st->print("%*s ", indentation, ""); ++ st->print_cr("(%u class%s)", _num_classes, (_num_classes == 1) ? "" : "es"); ++ ++ // Empty line ++ branchtracker.print(st); ++ st->cr(); ++ } ++ ++ if (_anon_classes != NULL) { ++ assert(_cld != NULL, "we have classes, we should have a CLD"); ++ for (LoadedClassInfo* lci = _anon_classes; lci; lci = lci->_next) { ++ branchtracker.print(st); ++ if (lci == _anon_classes) { // first iteration ++ st->print("%*s ", indentation, "Anonymous Classes:"); ++ } else { ++ st->print("%*s ", indentation, ""); ++ } ++ st->print("%s", lci->_klass->external_name()); ++ // For anonymous classes, also print CLD if verbose. Should be a different one than the primary CLD. ++ assert(lci->_cld != _cld, "must be"); ++ if (verbose) { ++ st->print(" (CLD: " PTR_FORMAT ")", p2i(lci->_cld)); ++ } ++ st->cr(); ++ } ++ branchtracker.print(st); ++ st->print("%*s ", indentation, ""); ++ st->print_cr("(%u anonymous class%s)", _num_anon_classes, (_num_anon_classes == 1) ? "" : "es"); ++ ++ // Empty line ++ branchtracker.print(st); ++ st->cr(); ++ } ++ ++ } // end: print_classes ++ ++ } // Pop branchtracker mark ++ ++ // Print children, recursively ++ LoaderTreeNode* c = _child; ++ while (c != NULL) { ++ c->print_with_child_nodes(st, branchtracker, print_classes, verbose); ++ c = c->_next; ++ } ++ ++ } ++ ++public: ++ ++ LoaderTreeNode(const oop loader_oop) ++ : _loader_oop(loader_oop), _cld(NULL) ++ , _child(NULL), _next(NULL) ++ , _classes(NULL), _anon_classes(NULL) ++ , _num_classes(0), _num_anon_classes(0) {} ++ ++ void set_cld(const ClassLoaderData* cld) { ++ assert(_cld == NULL, "there should be only one primary CLD per loader"); ++ _cld = cld; ++ } ++ ++ void add_child(LoaderTreeNode* info) { ++ info->_next = _child; ++ _child = info; ++ } ++ ++ void add_sibling(LoaderTreeNode* info) { ++ assert(info->_next == NULL, "must be"); ++ info->_next = _next; ++ _next = info; ++ } ++ ++ void add_classes(LoadedClassInfo* first_class, int num_classes, bool anonymous) { ++ LoadedClassInfo** p_list_to_add_to = anonymous ? &_anon_classes : &_classes; ++ // Search tail. ++ while ((*p_list_to_add_to) != NULL) { ++ p_list_to_add_to = &(*p_list_to_add_to)->_next; ++ } ++ *p_list_to_add_to = first_class; ++ if (anonymous) { ++ _num_anon_classes += num_classes; ++ } else { ++ _num_classes += num_classes; ++ } ++ } ++ ++ LoaderTreeNode* find(const oop loader_oop) { ++ LoaderTreeNode* result = NULL; ++ if (_loader_oop == loader_oop) { ++ result = this; ++ } else { ++ LoaderTreeNode* c = _child; ++ while (c != NULL && result == NULL) { ++ result = c->find(loader_oop); ++ c = c->_next; ++ } ++ } ++ return result; ++ } ++ ++ void print_with_child_nodes(outputStream* st, bool print_classes, bool print_add_info) const { ++ BranchTracker bwt; ++ print_with_child_nodes(st, bwt, print_classes, print_add_info); ++ } ++ ++}; ++ ++class LoadedClassCollectClosure : public KlassClosure { ++public: ++ LoadedClassInfo* _list; ++ const ClassLoaderData* _cld; ++ int _num_classes; ++ LoadedClassCollectClosure(const ClassLoaderData* cld) ++ : _list(NULL), _cld(cld), _num_classes(0) {} ++ void do_klass(Klass* k) { ++ LoadedClassInfo* lki = new LoadedClassInfo(k, _cld); ++ lki->_next = _list; ++ _list = lki; ++ _num_classes ++; ++ } ++}; ++ ++class LoaderInfoScanClosure : public CLDClosure { ++ ++ const bool _print_classes; ++ const bool _verbose; ++ LoaderTreeNode* _root; ++ ++ static void fill_in_classes(LoaderTreeNode* info, const ClassLoaderData* cld) { ++ assert(info != NULL && cld != NULL, "must be"); ++ LoadedClassCollectClosure lccc(cld); ++ const_cast(cld)->classes_do(&lccc); ++ if (lccc._num_classes > 0) { ++ info->add_classes(lccc._list, lccc._num_classes, cld->is_anonymous()); ++ } ++ } ++ ++ LoaderTreeNode* find_node_or_add_empty_node(oop loader_oop) { ++ ++ assert(_root != NULL, "root node must exist"); ++ ++ if (loader_oop == NULL) { ++ return _root; ++ } ++ ++ // Check if a node for this oop already exists. ++ LoaderTreeNode* info = _root->find(loader_oop); ++ ++ if (info == NULL) { ++ // It does not. Create a node. ++ info = new LoaderTreeNode(loader_oop); ++ ++ // Add it to tree. ++ LoaderTreeNode* parent_info = NULL; ++ ++ // Recursively add parent nodes if needed. ++ const oop parent_oop = java_lang_ClassLoader::parent(loader_oop); ++ if (parent_oop == NULL) { ++ parent_info = _root; ++ } else { ++ parent_info = find_node_or_add_empty_node(parent_oop); ++ } ++ assert(parent_info != NULL, "must be"); ++ ++ parent_info->add_child(info); ++ } ++ return info; ++ } ++ ++ ++public: ++ LoaderInfoScanClosure(bool print_classes, bool verbose) ++ : _print_classes(print_classes), _verbose(verbose), _root(NULL) { ++ _root = new LoaderTreeNode(NULL); ++ } ++ ++ void print_results(outputStream* st) const { ++ _root->print_with_child_nodes(st, _print_classes, _verbose); ++ } ++ ++ void do_cld (ClassLoaderData* cld) { ++ ++ // We do not display unloading loaders, for now. ++ if (cld->is_unloading()) { ++ return; ++ } ++ ++ const oop loader_oop = cld->class_loader(); ++ ++ LoaderTreeNode* info = find_node_or_add_empty_node(loader_oop); ++ assert(info != NULL, "must be"); ++ ++ // Update CLD in node, but only if this is the primary CLD for this loader. ++ if (cld->is_anonymous() == false) { ++ info->set_cld(cld); ++ } ++ ++ // Add classes. ++ fill_in_classes(info, cld); ++ } ++ ++}; ++ ++ ++class ClassLoaderHierarchyVMOperation : public VM_Operation { ++ outputStream* const _out; ++ const bool _show_classes; ++ const bool _verbose; ++public: ++ ClassLoaderHierarchyVMOperation(outputStream* out, bool show_classes, bool verbose) : ++ _out(out), _show_classes(show_classes), _verbose(verbose) ++ {} ++ ++ VMOp_Type type() const { ++ return VMOp_ClassLoaderHierarchyOperation; ++ } ++ ++ void doit() { ++ assert(SafepointSynchronize::is_at_safepoint(), "must be a safepoint"); ++ ResourceMark rm; ++ LoaderInfoScanClosure cl (_show_classes, _verbose); ++ ClassLoaderDataGraph::cld_do(&cl); ++ cl.print_results(_out); ++ } ++}; ++ ++// This command needs to be executed at a safepoint. ++void ClassLoaderHierarchyDCmd::execute(DCmdSource source, TRAPS) { ++ ClassLoaderHierarchyVMOperation op(output(), _show_classes.value(), _verbose.value()); ++ VMThread::execute(&op); ++} +\ No newline at end of file +diff --git a/hotspot/src/share/vm/classfile/classLoaderHierarchyDCmd.hpp b/hotspot/src/share/vm/classfile/classLoaderHierarchyDCmd.hpp +new file mode 100644 +index 0000000..49027e6 +--- /dev/null ++++ b/hotspot/src/share/vm/classfile/classLoaderHierarchyDCmd.hpp +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018 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 ++ * 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 HOTSPOT_SHARE_CLASSFILE_CLASSLOADERHIERARCHYDCMD_HPP_ ++#define HOTSPOT_SHARE_CLASSFILE_CLASSLOADERHIERARCHYDCMD_HPP_ ++ ++#include "services/diagnosticCommand.hpp" ++ ++class ClassLoaderHierarchyDCmd: public DCmdWithParser { ++ DCmdArgument _show_classes; ++ DCmdArgument _verbose; ++public: ++ ++ ClassLoaderHierarchyDCmd(outputStream* output, bool heap); ++ ++ static const char* name() { ++ return "VM.classloaders"; ++ } ++ ++ static const char* description() { ++ return "Prints classloader hierarchy."; ++ } ++ static const char* impact() { ++ return "Medium: Depends on number of class loaders and classes loaded."; ++ } ++ static const JavaPermission permission() { ++ JavaPermission p = {"java.lang.management.ManagementPermission", ++ "monitor", NULL}; ++ return p; ++ } ++ static int num_arguments(); ++ virtual void execute(DCmdSource source, TRAPS); ++ ++}; ++ ++#endif /* HOTSPOT_SHARE_CLASSFILE_CLASSLOADERHIERARCHYDCMD_HPP_ */ +\ No newline at end of file +diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp +index a8ba78b..3744040 100644 +--- a/hotspot/src/share/vm/runtime/vm_operations.hpp ++++ b/hotspot/src/share/vm/runtime/vm_operations.hpp +@@ -98,6 +98,7 @@ + template(RotateGCLog) \ + template(WhiteBoxOperation) \ + template(ClassLoaderStatsOperation) \ ++ template(ClassLoaderHierarchyOperation) \ + template(JFROldObject) \ + template(PrintClasses) \ + +diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp +index e4e6185..d3b91d9 100644 +--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp ++++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp +@@ -24,6 +24,7 @@ + + #include "precompiled.hpp" + #include "cds/dynamicArchive.hpp" ++#include "classfile/classLoaderHierarchyDCmd.hpp" + #include "classfile/classLoaderStats.hpp" + #include "gc_implementation/shared/vmGCOperations.hpp" + #include "runtime/javaCalls.hpp" +@@ -70,6 +71,7 @@ void DCmdRegistrant::register_dcmds(){ + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); ++ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + #ifdef LINUX + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + #endif // LINUX +diff --git a/hotspot/test/serviceability/dcmd/ClassLoaderHierarchyTest.java b/hotspot/test/serviceability/dcmd/ClassLoaderHierarchyTest.java +new file mode 100644 +index 0000000..378997d +--- /dev/null ++++ b/hotspot/test/serviceability/dcmd/ClassLoaderHierarchyTest.java +@@ -0,0 +1,213 @@ ++/* ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2018, 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 ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++/* ++ * @test ++ * @summary Test of diagnostic command VM.classloaders ++ * @library /testlibrary ++ * @modules java.base/jdk.internal.misc ++ * java.compiler ++ * java.management ++ * jdk.internal.jvmstat/sun.jvmstat.monitor ++ * @run testng ClassLoaderHierarchyTest ++ */ ++ ++import org.testng.Assert; ++import org.testng.annotations.Test; ++ ++import com.oracle.java.testlibrary.OutputAnalyzer; ++import com.oracle.java.testlibrary.CommandExecutor; ++import com.oracle.java.testlibrary.JMXExecutor; ++ ++import java.io.File; ++import java.io.FileInputStream; ++import java.io.IOException; ++import java.nio.ByteBuffer; ++import java.nio.channels.FileChannel; ++ ++public class ClassLoaderHierarchyTest { ++ ++ class EmptyDelegatingLoader extends ClassLoader { ++ EmptyDelegatingLoader(ClassLoader parent) { ++ super(parent); ++ } ++ } ++ ++ static void loadTestClassInLoaderAndCheck(String classname, ClassLoader loader) throws ClassNotFoundException { ++ Class c = Class.forName(classname, true, loader); ++ if (c.getClassLoader() != loader) { ++ Assert.fail(classname + " defined by wrong classloader: " + c.getClassLoader()); ++ } ++ } ++ ++//+-- ++// | ++// +-- "sun.misc.Launcher$ExtClassLoader", sun.misc.Launcher$ExtClassLoader ++// | | ++// | +-- "sun.misc.Launcher$AppClassLoader", sun.misc.Launcher$AppClassLoader ++// | ++// +-- "sun.reflect.DelegatingClassLoader", sun.reflect.DelegatingClassLoader ++// | ++// +-- "ClassLoaderHierarchyTest$TestClassLoader", ClassLoaderHierarchyTest$TestClassLoader ++// | | ++// | +-- "ClassLoaderHierarchyTest$TestClassLoader", ClassLoaderHierarchyTest$TestClassLoader ++// | ++// +-- "ClassLoaderHierarchyTest$EmptyDelegatingLoader", ClassLoaderHierarchyTest$EmptyDelegatingLoader ++// | | ++// | +-- "ClassLoaderHierarchyTest$EmptyDelegatingLoader", ClassLoaderHierarchyTest$EmptyDelegatingLoader ++// | | ++// | +-- "ClassLoaderHierarchyTest$TestClassLoader", ClassLoaderHierarchyTest$TestClassLoader ++// | ++// +-- "ClassLoaderHierarchyTest$EmptyDelegatingLoader", ClassLoaderHierarchyTest$EmptyDelegatingLoader ++// | ++// +-- "ClassLoaderHierarchyTest$EmptyDelegatingLoader", ClassLoaderHierarchyTest$EmptyDelegatingLoader ++// | ++// +-- "ClassLoaderHierarchyTest$TestClassLoader", ClassLoaderHierarchyTest$TestClassLoader ++// | ++// +-- "ClassLoaderHierarchyTest$TestClassLoader", ClassLoaderHierarchyTest$TestClassLoader ++// | ++// +-- "ClassLoaderHierarchyTest$TestClassLoader", ClassLoaderHierarchyTest$TestClassLoader ++ ++ ++ public void run(CommandExecutor executor) throws ClassNotFoundException { ++ ++ // A) one unnamed, two named loaders ++ ClassLoader unnamed_cl = new TestClassLoader(null); ++ ClassLoader named_child_cl = new TestClassLoader(unnamed_cl); ++ loadTestClassInLoaderAndCheck("TestClass2", unnamed_cl); ++ loadTestClassInLoaderAndCheck("TestClass2", named_child_cl); ++ ++ // B) A named CL with empty loaders as parents (JDK-8293156) ++ EmptyDelegatingLoader emptyLoader1 = new EmptyDelegatingLoader( null); ++ EmptyDelegatingLoader emptyLoader2 = new EmptyDelegatingLoader(emptyLoader1); ++ ClassLoader named_child_2_cl = new TestClassLoader(emptyLoader2); ++ loadTestClassInLoaderAndCheck("TestClass2", named_child_2_cl); ++ ++ // C) Test output for several *unnamed* class loaders, same class, same parents, ++ // and all these should be folded by default. ++ EmptyDelegatingLoader emptyLoader3 = new EmptyDelegatingLoader(null); ++ EmptyDelegatingLoader emptyLoader4 = new EmptyDelegatingLoader(emptyLoader3); ++ ClassLoader named_child_3_cl = new TestClassLoader(emptyLoader4); // Same names ++ ClassLoader named_child_4_cl = new TestClassLoader(emptyLoader4); ++ ClassLoader named_child_5_cl = new TestClassLoader(emptyLoader4); ++ loadTestClassInLoaderAndCheck("TestClass2", named_child_3_cl); ++ loadTestClassInLoaderAndCheck("TestClass2", named_child_4_cl); ++ loadTestClassInLoaderAndCheck("TestClass2", named_child_5_cl); ++ ++ // First test: simple output, no classes displayed ++ OutputAnalyzer output = executor.execute("VM.classloaders"); ++ // (A) ++ output.shouldContain("+-- "); ++ output.shouldContain(" +-- \"sun.misc.Launcher$ExtClassLoader\", sun.misc.Launcher$ExtClassLoader"); ++ output.shouldContain(" | +-- \"sun.misc.Launcher$AppClassLoader\", sun.misc.Launcher$AppClassLoader"); ++ output.shouldContain(" +-- \"sun.reflect.DelegatingClassLoader\", sun.reflect.DelegatingClassLoader"); ++ output.shouldContain(" +-- \"ClassLoaderHierarchyTest$TestClassLoader\", ClassLoaderHierarchyTest$TestClassLoader"); ++ output.shouldContain(" | +-- \"ClassLoaderHierarchyTest$TestClassLoader\", ClassLoaderHierarchyTest$TestClassLoader"); ++ // (B) ++ output.shouldContain(" +-- \"ClassLoaderHierarchyTest$EmptyDelegatingLoader\", ClassLoaderHierarchyTest$EmptyDelegatingLoader"); ++ output.shouldContain(" | +-- \"ClassLoaderHierarchyTest$EmptyDelegatingLoader\", ClassLoaderHierarchyTest$EmptyDelegatingLoader"); ++ output.shouldContain(" | +-- \"ClassLoaderHierarchyTest$TestClassLoader\", ClassLoaderHierarchyTest$TestClassLoader"); ++ // (C) ++ output.shouldContain(" +-- \"ClassLoaderHierarchyTest$EmptyDelegatingLoader\", ClassLoaderHierarchyTest$EmptyDelegatingLoader"); ++ output.shouldContain(" +-- \"ClassLoaderHierarchyTest$EmptyDelegatingLoader\", ClassLoaderHierarchyTest$EmptyDelegatingLoader"); ++ output.shouldContain(" +-- \"ClassLoaderHierarchyTest$TestClassLoader\", ClassLoaderHierarchyTest$TestClassLoader"); ++ ++ // Second test: print with classes. ++ output = executor.execute("VM.classloaders show-classes"); ++ output.shouldContain(""); ++ output.shouldContain("java.lang.Object"); ++ output.shouldContain("java.lang.Enum"); ++ output.shouldContain("java.lang.NullPointerException"); ++ output.shouldContain("TestClass2"); ++ } ++ ++ static class TestClassLoader extends ClassLoader { ++ ++ public TestClassLoader() { ++ super(); ++ } ++ ++ public TestClassLoader(ClassLoader parent) { ++ super(parent); ++ } ++ ++ public static final String CLASS_NAME = "TestClass2"; ++ ++ static ByteBuffer readClassFile(String name) ++ { ++ File f = new File(System.getProperty("test.classes", "."), ++ name); ++ try (FileInputStream fin = new FileInputStream(f); ++ FileChannel fc = fin.getChannel()) ++ { ++ return fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size()); ++ } catch (IOException e) { ++ Assert.fail("Can't open file: " + name, e); ++ } ++ ++ /* Will not reach here as Assert.fail() throws exception */ ++ return null; ++ } ++ ++ protected Class loadClass(String name, boolean resolve) ++ throws ClassNotFoundException ++ { ++ Class c; ++ if (!CLASS_NAME.equals(name)) { ++ c = super.loadClass(name, resolve); ++ } else { ++ // should not delegate to the system class loader ++ c = findClass(name); ++ if (resolve) { ++ resolveClass(c); ++ } ++ } ++ return c; ++ } ++ ++ protected Class findClass(String name) ++ throws ClassNotFoundException ++ { ++ if (!CLASS_NAME.equals(name)) { ++ throw new ClassNotFoundException("Unexpected class: " + name); ++ } ++ return defineClass(name, readClassFile(name + ".class"), null); ++ } ++ ++ } ++ ++ @Test ++ public void jmx() throws ClassNotFoundException { ++ run(new JMXExecutor()); ++ } ++ ++} ++ ++class TestClass2 { ++ static { ++ Runnable r = () -> System.out.println("Hello"); ++ r.run(); ++ } ++} +\ No newline at end of file +-- +1.8.3.1 diff --git a/8204595-add-more-thread-related-system-settings-info.patch b/8204595-add-more-thread-related-system-settings-info.patch new file mode 100644 index 0000000..47dc73d --- /dev/null +++ b/8204595-add-more-thread-related-system-settings-info.patch @@ -0,0 +1,69 @@ +From 16caa051cb7299312cdaf9d79eaef01d294474f6 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Thu, 15 Dec 2022 17:06:41 +0800 +Subject: [PATCH 21/33] I68TO2: 8204595: add more thread-related system settings info + to hs_error file on Linux +--- + hotspot/src/os/linux/vm/os_linux.cpp | 22 +++++++++++++++++++++- + hotspot/src/os/linux/vm/os_linux.hpp | 1 + + 2 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp +index abf2031..1ec68ab 100644 +--- a/hotspot/src/os/linux/vm/os_linux.cpp ++++ b/hotspot/src/os/linux/vm/os_linux.cpp +@@ -2249,6 +2249,8 @@ void os::print_os_info(outputStream* st) { + + os::Linux::print_process_memory_info(st); + ++ os::Linux::print_proc_sys_info(st); ++ + os::Linux::print_container_info(st); + } + +@@ -2390,6 +2392,24 @@ void os::Linux::print_process_memory_info(outputStream* st) { + + } + ++void os::Linux::print_proc_sys_info(outputStream* st) { ++ st->cr(); ++ st->print_cr("/proc/sys/kernel/threads-max (system-wide limit on the number of threads):"); ++ _print_ascii_file("/proc/sys/kernel/threads-max", st); ++ st->cr(); ++ st->cr(); ++ ++ st->print_cr("/proc/sys/vm/max_map_count (maximum number of memory map areas a process may have):"); ++ _print_ascii_file("/proc/sys/vm/max_map_count", st); ++ st->cr(); ++ st->cr(); ++ ++ st->print_cr("/proc/sys/kernel/pid_max (system-wide limit on number of process identifiers):"); ++ _print_ascii_file("/proc/sys/kernel/pid_max", st); ++ st->cr(); ++ st->cr(); ++} ++ + void os::Linux::print_container_info(outputStream* st) { + if (!OSContainer::is_containerized()) { + return; +@@ -6928,4 +6948,4 @@ bool os::trim_native_heap(os::size_change_t* rss_change) { + #else + return false; // musl + #endif +-} +\ No newline at end of file ++} +diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp +index 6c27bcb..4ee2c9b 100644 +--- a/hotspot/src/os/linux/vm/os_linux.hpp ++++ b/hotspot/src/os/linux/vm/os_linux.hpp +@@ -125,6 +125,7 @@ class Linux { + static void print_container_info(outputStream* st); + static void print_distro_info(outputStream* st); + static void print_libversion_info(outputStream* st); ++ static void print_proc_sys_info(outputStream* st); + + public: + static bool _stack_is_executable; +-- +1.8.3.1 diff --git a/8219584-Try-to-dump-error-file-by-thread-which-cause.patch b/8219584-Try-to-dump-error-file-by-thread-which-cause.patch new file mode 100644 index 0000000..fcf7186 --- /dev/null +++ b/8219584-Try-to-dump-error-file-by-thread-which-cause.patch @@ -0,0 +1,407 @@ +From b61cd484f501a1fe7d49c336878a4b8398e727d9 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Thu, 15 Dec 2022 14:28:05 +0800 +Subject: [PATCH 20/33] I68TO2: 8219584: Try to dump error file by thread which causes + safepoint timeout +--- + hotspot/src/os/posix/vm/os_posix.cpp | 31 ++++++- + hotspot/src/os/windows/vm/os_windows.cpp | 9 ++ + hotspot/src/share/vm/runtime/globals.hpp | 2 +- + hotspot/src/share/vm/runtime/os.hpp | 4 + + hotspot/src/share/vm/runtime/safepoint.cpp | 21 +++-- + hotspot/src/share/vm/runtime/vmThread.cpp | 36 +++++--- + hotspot/src/share/vm/runtime/vmThread.hpp | 10 ++- + hotspot/src/share/vm/utilities/vmError.cpp | 3 + + .../Safepoint/TestAbortVMOnSafepointTimeout.java | 97 ++++++++++++++++++++++ + 9 files changed, 195 insertions(+), 18 deletions(-) + create mode 100644 hotspot/test/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java + +diff --git a/hotspot/src/os/posix/vm/os_posix.cpp b/hotspot/src/os/posix/vm/os_posix.cpp +index e7f1fdd..d2663bd 100644 +--- a/hotspot/src/os/posix/vm/os_posix.cpp ++++ b/hotspot/src/os/posix/vm/os_posix.cpp +@@ -26,6 +26,7 @@ + #include "prims/jvm.h" + #include "runtime/frame.inline.hpp" + #include "runtime/os.hpp" ++#include "utilities/events.hpp" + #include "utilities/vmError.hpp" + + #include +@@ -814,6 +815,15 @@ static bool get_signal_code_description(const siginfo_t* si, enum_sigcode_desc_t + return true; + } + ++bool os::signal_sent_by_kill(const void* siginfo) { ++ const siginfo_t* const si = (const siginfo_t*)siginfo; ++ return si->si_code == SI_USER || si->si_code == SI_QUEUE ++#ifdef SI_TKILL ++ || si->si_code == SI_TKILL ++#endif ++ ; ++} ++ + // A POSIX conform, platform-independend siginfo print routine. + // Short print out on one line. + void os::Posix::print_siginfo_brief(outputStream* os, const siginfo_t* si) { +@@ -844,7 +854,7 @@ void os::Posix::print_siginfo_brief(outputStream* os, const siginfo_t* si) { + const int me = (int) ::getpid(); + const int pid = (int) si->si_pid; + +- if (si->si_code == SI_USER || si->si_code == SI_QUEUE) { ++ if (signal_sent_by_kill(si)) { + if (IS_VALID_PID(pid) && pid != me) { + os->print(", sent from pid: %d (uid: %d)", pid, (int) si->si_uid); + } +@@ -860,6 +870,25 @@ void os::Posix::print_siginfo_brief(outputStream* os, const siginfo_t* si) { + } + } + ++bool os::signal_thread(Thread* thread, int sig, const char* reason) { ++ OSThread* osthread = thread->osthread(); ++ if (osthread) { ++#if defined (SOLARIS) ++ // Note: we cannot use pthread_kill on Solaris - not because ++ // its missing, but because we do not have the pthread_t id. ++ int status = thr_kill(osthread->thread_id(), sig); ++#else ++ int status = pthread_kill(osthread->pthread_id(), sig); ++#endif ++ if (status == 0) { ++ Events::log(Thread::current(), "sent signal %d to Thread " INTPTR_FORMAT " because %s.", ++ sig, p2i(thread), reason); ++ return true; ++ } ++ } ++ return false; ++} ++ + bool os::Posix::is_root(uid_t uid){ + return ROOT_UID == uid; + } +diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp +index cc31126..cf1036c 100644 +--- a/hotspot/src/os/windows/vm/os_windows.cpp ++++ b/hotspot/src/os/windows/vm/os_windows.cpp +@@ -1877,6 +1877,11 @@ void os::print_memory_info(outputStream* st) { + st->cr(); + } + ++bool os::signal_sent_by_kill(const void* siginfo) { ++ // TODO: Is this possible? ++ return false; ++} ++ + void os::print_siginfo(outputStream *st, void *siginfo) { + EXCEPTION_RECORD* er = (EXCEPTION_RECORD*)siginfo; + st->print("siginfo:"); +@@ -1911,6 +1916,10 @@ void os::print_siginfo(outputStream *st, void *siginfo) { + st->cr(); + } + ++bool os::signal_thread(Thread* thread, int sig, const char* reason) { ++ // TODO: Can we kill thread? ++ return false; ++} + + int os::vsnprintf(char* buf, size_t len, const char* fmt, va_list args) { + #if _MSC_VER >= 1900 +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 10e4e7f..64d40e0 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -650,7 +650,7 @@ class CommandLineFlags { + "Print out every time compilation is longer than " \ + "a given threshold") \ + \ +- develop(bool, SafepointALot, false, \ ++ diagnostic(bool, SafepointALot, false, \ + "Generate a lot of safepoints. This works with " \ + "GuaranteedSafepointInterval") \ + \ +diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp +index 5f41e96..092459c 100644 +--- a/hotspot/src/share/vm/runtime/os.hpp ++++ b/hotspot/src/share/vm/runtime/os.hpp +@@ -492,6 +492,9 @@ class os: AllStatic { + static void pd_start_thread(Thread* thread); + static void start_thread(Thread* thread); + ++ // Returns true if successful. ++ static bool signal_thread(Thread* thread, int sig, const char* reason); ++ + static void initialize_thread(Thread* thr); + static void free_thread(OSThread* osthread); + +@@ -653,6 +656,7 @@ class os: AllStatic { + static void print_environment_variables(outputStream* st, const char** env_list, char* buffer, int len); + static void print_context(outputStream* st, void* context); + static void print_register_info(outputStream* st, void* context); ++ static bool signal_sent_by_kill(const void* siginfo); + static void print_siginfo(outputStream* st, void* siginfo); + static void print_signal_handlers(outputStream* st, char* buf, size_t buflen); + static void print_date_and_time(outputStream* st, char* buf, size_t buflen); +diff --git a/hotspot/src/share/vm/runtime/safepoint.cpp b/hotspot/src/share/vm/runtime/safepoint.cpp +index 440617c..8408bed 100644 +--- a/hotspot/src/share/vm/runtime/safepoint.cpp ++++ b/hotspot/src/share/vm/runtime/safepoint.cpp +@@ -476,8 +476,7 @@ void SafepointSynchronize::begin() { + GC_locker::set_jni_lock_count(_current_jni_active_count); + + if (TraceSafepoint) { +- VM_Operation *op = VMThread::vm_operation(); +- tty->print_cr("Entering safepoint region: %s", (op != NULL) ? op->name() : "no vm operation"); ++ tty->print_cr("Entering safepoint region: %s", VMThread::vm_safepoint_description()); + } + + RuntimeService::record_safepoint_synchronized(); +@@ -929,11 +928,23 @@ void SafepointSynchronize::print_safepoint_timeout(SafepointTimeoutReason reason + // To debug the long safepoint, specify both AbortVMOnSafepointTimeout & + // ShowMessageBoxOnError. + if (AbortVMOnSafepointTimeout) { ++ // Send the blocking thread a signal to terminate and write an error file. ++ for (JavaThread *cur_thread = Threads::first(); cur_thread; ++ cur_thread = cur_thread->next()) { ++ ThreadSafepointState *cur_state = cur_thread->safepoint_state(); ++ if (cur_thread->thread_state() != _thread_blocked && ++ ((reason == _spinning_timeout && cur_state->is_running()) || ++ (reason == _blocking_timeout && !cur_state->has_called_back()))) { ++ if (!os::signal_thread(cur_thread, SIGILL, "blocking a safepoint")) { ++ break; // Could not send signal. Report fatal error. ++ } ++ // Give cur_thread a chance to report the error and terminate the VM. ++ os::sleep(Thread::current(), 3000, false); ++ } ++ } + char msg[1024]; +- VM_Operation *op = VMThread::vm_operation(); + sprintf(msg, "Safepoint sync time longer than " INTX_FORMAT "ms detected when executing %s.", +- SafepointTimeoutDelay, +- op != NULL ? op->name() : "no vm operation"); ++ SafepointTimeoutDelay, VMThread::vm_safepoint_description()); + fatal(msg); + } + } +diff --git a/hotspot/src/share/vm/runtime/vmThread.cpp b/hotspot/src/share/vm/runtime/vmThread.cpp +index b27c287..4f1695e 100644 +--- a/hotspot/src/share/vm/runtime/vmThread.cpp ++++ b/hotspot/src/share/vm/runtime/vmThread.cpp +@@ -217,6 +217,7 @@ VMThread* VMThread::_vm_thread = NULL; + VM_Operation* VMThread::_cur_vm_operation = NULL; + VMOperationQueue* VMThread::_vm_queue = NULL; + PerfCounter* VMThread::_perf_accumulated_vm_operation_time = NULL; ++const char* VMThread::_no_op_reason = NULL; + + + void VMThread::create() { +@@ -290,6 +291,7 @@ void VMThread::run() { + } + + // 4526887 let VM thread exit at Safepoint ++ _no_op_reason = "Halt"; + SafepointSynchronize::begin(); + + if (VerifyBeforeExit) { +@@ -422,6 +424,25 @@ void VMThread::evaluate_operation(VM_Operation* op) { + } + } + ++bool VMThread::no_op_safepoint_needed(bool check_time) { ++ if (SafepointALot) { ++ _no_op_reason = "SafepointALot"; ++ return true; ++ } ++ if (!SafepointSynchronize::is_cleanup_needed()) { ++ return false; ++ } ++ if (check_time) { ++ long interval = SafepointSynchronize::last_non_safepoint_interval(); ++ bool max_time_exceeded = GuaranteedSafepointInterval != 0 && ++ (interval > GuaranteedSafepointInterval); ++ if (!max_time_exceeded) { ++ return false; ++ } ++ } ++ _no_op_reason = "Cleanup"; ++ return true; ++} + + void VMThread::loop() { + assert(_cur_vm_operation == NULL, "no current one should be executing"); +@@ -460,8 +481,7 @@ void VMThread::loop() { + exit(-1); + } + +- if (timedout && (SafepointALot || +- SafepointSynchronize::is_cleanup_needed())) { ++ if (timedout && VMThread::no_op_safepoint_needed(false)) { + MutexUnlockerEx mul(VMOperationQueue_lock, + Mutex::_no_safepoint_check_flag); + // Force a safepoint since we have not had one for at least +@@ -585,14 +605,10 @@ void VMThread::loop() { + // + // We want to make sure that we get to a safepoint regularly. + // +- if (SafepointALot || SafepointSynchronize::is_cleanup_needed()) { +- long interval = SafepointSynchronize::last_non_safepoint_interval(); +- bool max_time_exceeded = GuaranteedSafepointInterval != 0 && (interval > GuaranteedSafepointInterval); +- if (SafepointALot || max_time_exceeded) { +- HandleMark hm(VMThread::vm_thread()); +- SafepointSynchronize::begin(); +- SafepointSynchronize::end(); +- } ++ if (VMThread::no_op_safepoint_needed(true)) { ++ HandleMark hm(VMThread::vm_thread()); ++ SafepointSynchronize::begin(); ++ SafepointSynchronize::end(); + } + } + } +diff --git a/hotspot/src/share/vm/runtime/vmThread.hpp b/hotspot/src/share/vm/runtime/vmThread.hpp +index a6d1ad3..d8af0d9 100644 +--- a/hotspot/src/share/vm/runtime/vmThread.hpp ++++ b/hotspot/src/share/vm/runtime/vmThread.hpp +@@ -100,7 +100,12 @@ class VMThread: public NamedThread { + static Monitor * _terminate_lock; + static PerfCounter* _perf_accumulated_vm_operation_time; + ++ static const char* _no_op_reason; ++ ++ static bool no_op_safepoint_needed(bool check_time); ++ + void evaluate_operation(VM_Operation* op); ++ + public: + // Constructor + VMThread(); +@@ -123,7 +128,10 @@ class VMThread: public NamedThread { + static void execute(VM_Operation* op); + + // Returns the current vm operation if any. +- static VM_Operation* vm_operation() { return _cur_vm_operation; } ++ static VM_Operation* vm_operation() { return _cur_vm_operation; } ++ ++ // Returns the current vm operation name or set reason ++ static const char* vm_safepoint_description() { return _cur_vm_operation != NULL ? _cur_vm_operation->name() : _no_op_reason; }; + + // Returns the single instance of VMThread. + static VMThread* vm_thread() { return _vm_thread; } +diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp +index 9b40a34..261591d 100644 +--- a/hotspot/src/share/vm/utilities/vmError.cpp ++++ b/hotspot/src/share/vm/utilities/vmError.cpp +@@ -460,6 +460,9 @@ void VMError::report(outputStream* st) { + st->print("%s", buf); + st->print(" (0x%x)", _id); // signal number + st->print(" at pc=" PTR_FORMAT, _pc); ++ if (_siginfo != NULL && os::signal_sent_by_kill(_siginfo)) { ++ st->print(" (sent by kill)"); ++ } + } else { + if (should_report_bug(_id)) { + st->print("Internal Error"); +diff --git a/hotspot/test/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java b/hotspot/test/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java +new file mode 100644 +index 0000000..a097bdc +--- /dev/null ++++ b/hotspot/test/runtime/Safepoint/TestAbortVMOnSafepointTimeout.java +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (c) 2019, SAP SE. All rights reserved. ++ * Copyright (c) 2021, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import com.oracle.java.testlibrary.*; ++ ++/* ++ * @test TestAbortVMOnSafepointTimeout ++ * @summary Check if VM can kill thread which doesn't reach safepoint. ++ * @bug 8219584 8227528 ++ * @library /testlibrary ++ * ++ */ ++ ++public class TestAbortVMOnSafepointTimeout { ++ ++ public static void main(String[] args) throws Exception { ++ if (args.length > 0) { ++ int result = test_loop(3); ++ System.out.println("This message would occur after some time with result " + result); ++ return; ++ } ++ ++ testWith(500, 500); ++ } ++ ++ static int test_loop(int x) { ++ int sum = 0; ++ if (x != 0) { ++ // Long running loop without safepoint. ++ for (int y = 1; y < Integer.MAX_VALUE; ++y) { ++ if (y % x == 0) ++sum; ++ } ++ } ++ return sum; ++ } ++ ++ public static void testWith(int sfpt_interval, int timeout_delay) throws Exception { ++ // -XX:-UseCountedLoopSafepoints - is used to prevent the loop ++ // in test_loop() to poll for safepoints. ++ // -XX:LoopStripMiningIter=0 and -XX:LoopUnrollLimit=0 - are ++ // used to prevent optimizations over the loop in test_loop() ++ // since we actually want it to provoke a safepoint timeout. ++ // -XX:-UseBiasedLocking - is used to prevent biased locking ++ // handshakes from changing the timing of this test. ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( ++ "-XX:+UnlockDiagnosticVMOptions", ++ "-XX:-UseBiasedLocking", ++ "-XX:+SafepointTimeout", ++ "-XX:+SafepointALot", ++ "-XX:+AbortVMOnSafepointTimeout", ++ "-XX:SafepointTimeoutDelay=" + timeout_delay, ++ "-XX:GuaranteedSafepointInterval=" + sfpt_interval, ++ "-XX:-TieredCompilation", ++ "-XX:-UseCountedLoopSafepoints", ++ "-XX:LoopUnrollLimit=0", ++ "-XX:CompileCommand=compileonly,TestAbortVMOnSafepointTimeout::test_loop", ++ "-Xcomp", ++ "-XX:-CreateMinidumpOnCrash", ++ "-Xms64m", ++ "TestAbortVMOnSafepointTimeout", ++ "runTestLoop" ++ ); ++ ++ OutputAnalyzer output = new OutputAnalyzer(pb.start()); ++ if (Platform.isWindows()) { ++ output.shouldMatch("Safepoint sync time longer than"); ++ } else { ++ output.shouldMatch("SIGILL"); ++ if (Platform.isLinux()) { ++ output.shouldMatch("(sent by kill)"); ++ } ++ output.shouldMatch("TestAbortVMOnSafepointTimeout.test_loop"); ++ } ++ output.shouldNotHaveExitValue(0); ++ } ++} +-- +1.8.3.1 diff --git a/8229517-Support-for-optional-asynchronous-buffered-l.patch b/8229517-Support-for-optional-asynchronous-buffered-l.patch new file mode 100644 index 0000000..5a43c8f --- /dev/null +++ b/8229517-Support-for-optional-asynchronous-buffered-l.patch @@ -0,0 +1,697 @@ +From 577f318d824d91e5deb8b6b82dd211583cb93cac Mon Sep 17 00:00:00 2001 +From: eapen +Date: Thu, 15 Dec 2022 10:37:31 +0800 +Subject: [PATCH 18/33] I68TO2: 8229517: Support for optional asynchronous/buffered + logging +--- + hotspot/src/os/windows/vm/os_windows.cpp | 1 + + hotspot/src/share/vm/runtime/arguments.cpp | 10 ++ + hotspot/src/share/vm/runtime/globals.hpp | 9 ++ + hotspot/src/share/vm/runtime/init.cpp | 2 + + hotspot/src/share/vm/runtime/logAsyncWriter.cpp | 164 ++++++++++++++++++++++++ + hotspot/src/share/vm/runtime/logAsyncWriter.hpp | 159 +++++++++++++++++++++++ + hotspot/src/share/vm/runtime/os.hpp | 1 + + hotspot/src/share/vm/runtime/thread.cpp | 26 +++- + hotspot/src/share/vm/runtime/vmStructs.cpp | 2 + + hotspot/src/share/vm/utilities/linkedlist.hpp | 47 +++++-- + hotspot/src/share/vm/utilities/ostream.cpp | 26 ++++ + hotspot/src/share/vm/utilities/ostream.hpp | 3 + + 12 files changed, 440 insertions(+), 10 deletions(-) + create mode 100644 hotspot/src/share/vm/runtime/logAsyncWriter.cpp + create mode 100644 hotspot/src/share/vm/runtime/logAsyncWriter.hpp + +diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp +index 25122de..cc31126 100644 +--- a/hotspot/src/os/windows/vm/os_windows.cpp ++++ b/hotspot/src/os/windows/vm/os_windows.cpp +@@ -562,6 +562,7 @@ bool os::create_thread(Thread* thread, ThreadType thr_type, size_t stack_size) { + case os::pgc_thread: + case os::cgc_thread: + case os::watcher_thread: ++ case os::asynclog_thread: + if (VMThreadStackSize > 0) stack_size = (size_t)(VMThreadStackSize * K); + break; + } +diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp +index 91e2ce0..fba3d4b 100644 +--- a/hotspot/src/share/vm/runtime/arguments.cpp ++++ b/hotspot/src/share/vm/runtime/arguments.cpp +@@ -2269,6 +2269,16 @@ bool Arguments::verify_percentage(uintx value, const char* name) { + // no gc log rotation when log file not supplied or + // NumberOfGCLogFiles is 0 + void check_gclog_consistency() { ++ if (UseAsyncGCLog) { ++ if (Arguments::gc_log_filename() == NULL) { ++ jio_fprintf(defaultStream::output_stream(), ++ "To enable Async GC log, use -Xloggc: -XX:UseAsyncGCLog\n" ++ "Async GC log is turned off\n"); ++ UseAsyncGCLog = false; ++ ++ } ++ } ++ + if (UseGCLogFileRotation) { + if ((Arguments::gc_log_filename() == NULL) || (NumberOfGCLogFiles == 0)) { + jio_fprintf(defaultStream::output_stream(), +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 41b1392..10e4e7f 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -4104,6 +4104,15 @@ class CommandLineFlags { + \ + JFR_ONLY(product(bool, LogJFR, false, \ + "Enable JFR logging (consider +Verbose)")) \ ++ \ ++ product(bool, UseAsyncGCLog, false, \ ++ "Enable asynchronous GC logging") \ ++ \ ++ product(uintx, AsyncLogBufferSize, 2*M, \ ++ "Memory budget (in bytes) for the buffer of Asynchronous") \ ++ \ ++ diagnostic(bool, PrintAsyncGCLog, false, \ ++ "Print some information of Async GC Log") \ + + /* + * Macros for factoring of globals +diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp +index d2e0f22..b185409 100644 +--- a/hotspot/src/share/vm/runtime/init.cpp ++++ b/hotspot/src/share/vm/runtime/init.cpp +@@ -32,6 +32,7 @@ + #include "runtime/handles.inline.hpp" + #include "runtime/icache.hpp" + #include "runtime/init.hpp" ++#include "runtime/logAsyncWriter.hpp" + #include "runtime/safepoint.hpp" + #include "runtime/sharedRuntime.hpp" + #include "services/memTracker.hpp" +@@ -106,6 +107,7 @@ jint init_globals() { + if (status != JNI_OK) + return status; + ++ AsyncLogWriter::initialize(); + interpreter_init(); // before any methods loaded + invocationCounter_init(); // before any methods loaded + marksweep_init(); +diff --git a/hotspot/src/share/vm/runtime/logAsyncWriter.cpp b/hotspot/src/share/vm/runtime/logAsyncWriter.cpp +new file mode 100644 +index 0000000..750a23f +--- /dev/null ++++ b/hotspot/src/share/vm/runtime/logAsyncWriter.cpp +@@ -0,0 +1,164 @@ ++/* ++ * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++#include "precompiled.hpp" ++#include "runtime/atomic.hpp" ++#include "runtime/logAsyncWriter.hpp" ++#include "utilities/ostream.hpp" ++ ++class AsyncLogWriter::AsyncLogLocker : public StackObj { ++ public: ++ AsyncLogLocker() { ++ assert(_instance != NULL, "AsyncLogWriter::_lock is unavailable"); ++ _instance->_lock.wait(); ++ } ++ ++ ~AsyncLogLocker() { ++ _instance->_lock.signal(); ++ } ++}; ++ ++void AsyncLogWriter::enqueue_locked(const AsyncLogMessage& msg) { ++ if (_buffer.size() >= _buffer_max_size) { ++ // drop the enqueueing message. ++ os::free(msg.message()); ++ return; ++ } ++ ++ assert(_buffer.size() < _buffer_max_size, "_buffer is over-sized."); ++ _buffer.push_back(msg); ++ _sem.signal(); ++} ++ ++void AsyncLogWriter::enqueue(const char* msg) { ++ AsyncLogMessage m(os::strdup(msg)); ++ ++ { // critical area ++ AsyncLogLocker locker; ++ enqueue_locked(m); ++ } ++} ++ ++AsyncLogWriter::AsyncLogWriter() ++ : NamedThread(), ++ _lock(1), _sem(0), _io_sem(1), ++ _initialized(false), ++ _buffer_max_size(AsyncLogBufferSize / sizeof(AsyncLogMessage)) { ++ if (os::create_thread(this, os::asynclog_thread)) { ++ _initialized = true; ++ set_name("AsyncLog Thread"); ++ } else { ++ if (PrintAsyncGCLog) { ++ tty->print_cr("AsyncLogging failed to create thread. Falling back to synchronous logging."); ++ } ++ } ++ ++ if (PrintAsyncGCLog) { ++ tty->print_cr("The maximum entries of AsyncLogBuffer: " SIZE_FORMAT ", estimated memory use: " SIZE_FORMAT " bytes", ++ _buffer_max_size, AsyncLogBufferSize); ++ } ++} ++ ++void AsyncLogWriter::write() { ++ // Use kind of copy-and-swap idiom here. ++ // Empty 'logs' swaps the content with _buffer. ++ // Along with logs destruction, all processed messages are deleted. ++ // ++ // The operation 'pop_all()' is done in O(1). All I/O jobs are then performed without ++ // lock protection. This guarantees I/O jobs don't block logsites. ++ AsyncLogBuffer logs; ++ bool own_io = false; ++ ++ { // critical region ++ AsyncLogLocker locker; ++ ++ _buffer.pop_all(&logs); ++ own_io = _io_sem.trywait(); ++ } ++ ++ LinkedListIterator it(logs.head()); ++ if (!own_io) { ++ _io_sem.wait(); ++ } ++ ++ bool flush = false; ++ while (!it.is_empty()) { ++ AsyncLogMessage* e = it.next(); ++ char* msg = e->message(); ++ ++ if (msg != NULL) { ++ flush = true; ++ ((gcLogFileStream*)gclog_or_tty)->write_blocking(msg, strlen(msg)); ++ os::free(msg); ++ } ++ } ++ if (flush) { ++ ((gcLogFileStream*)gclog_or_tty)->fileStream::flush(); ++ } ++ _io_sem.signal(); ++} ++ ++void AsyncLogWriter::run() { ++ while (true) { ++ // The value of a semphore cannot be negative. Therefore, the current thread falls asleep ++ // when its value is zero. It will be waken up when new messages are enqueued. ++ _sem.wait(); ++ write(); ++ } ++} ++ ++AsyncLogWriter* AsyncLogWriter::_instance = NULL; ++ ++void AsyncLogWriter::initialize() { ++ if (!UseAsyncGCLog) return; ++ ++ assert(_instance == NULL, "initialize() should only be invoked once."); ++ ++ AsyncLogWriter* self = new AsyncLogWriter(); ++ if (self->_initialized) { ++ OrderAccess::release_store_ptr(&AsyncLogWriter::_instance, self); ++ os::start_thread(self); ++ if (PrintAsyncGCLog) { ++ tty->print_cr("Async logging thread started."); ++ } ++ } ++} ++ ++AsyncLogWriter* AsyncLogWriter::instance() { ++ return _instance; ++} ++ ++// write() acquires and releases _io_sem even _buffer is empty. ++// This guarantees all logging I/O of dequeued messages are done when it returns. ++void AsyncLogWriter::flush() { ++ if (_instance != NULL) { ++ _instance->write(); ++ } ++} ++ ++void AsyncLogWriter::print_on(outputStream* st) const{ ++ st->print("\"%s\" ", name()); ++ Thread::print_on(st); ++ st->cr(); ++} +diff --git a/hotspot/src/share/vm/runtime/logAsyncWriter.hpp b/hotspot/src/share/vm/runtime/logAsyncWriter.hpp +new file mode 100644 +index 0000000..5242426 +--- /dev/null ++++ b/hotspot/src/share/vm/runtime/logAsyncWriter.hpp +@@ -0,0 +1,159 @@ ++/* ++ * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * 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 SHARE_VM_RUNTIME_LOGASYNCWRITER_HPP ++#define SHARE_VM_RUNTIME_LOGASYNCWRITER_HPP ++#include "memory/resourceArea.hpp" ++#include "runtime/semaphore.hpp" ++#include "utilities/linkedlist.hpp" ++ ++template ++class LinkedListDeque : private LinkedListImpl { ++ private: ++ LinkedListNode* _tail; ++ size_t _size; ++ ++ public: ++ LinkedListDeque() : _tail(NULL), _size(0) {} ++ void push_back(const E& e) { ++ if (!_tail) { ++ _tail = this->add(e); ++ } else { ++ _tail = this->insert_after(e, _tail); ++ } ++ ++ ++_size; ++ } ++ ++ // pop all elements to logs. ++ void pop_all(LinkedList* logs) { ++ logs->move(static_cast* >(this)); ++ _tail = NULL; ++ _size = 0; ++ } ++ ++ void pop_all(LinkedListDeque* logs) { ++ logs->_size = _size; ++ logs->_tail = _tail; ++ pop_all(static_cast* >(logs)); ++ } ++ ++ void pop_front() { ++ LinkedListNode* h = this->unlink_head(); ++ if (h == _tail) { ++ _tail = NULL; ++ } ++ ++ if (h != NULL) { ++ --_size; ++ this->delete_node(h); ++ } ++ } ++ ++ size_t size() const { return _size; } ++ ++ const E* front() const { ++ return this->_head == NULL ? NULL : this->_head->peek(); ++ } ++ ++ const E* back() const { ++ return _tail == NULL ? NULL : _tail->peek(); ++ } ++ ++ LinkedListNode* head() const { ++ return this->_head; ++ } ++}; ++ ++class AsyncLogMessage { ++ char* _message; ++ ++public: ++ AsyncLogMessage(char* msg) ++ : _message(msg) {} ++ ++ // placeholder for LinkedListImpl. ++ bool equals(const AsyncLogMessage& o) const { return false; } ++ ++ char* message() const { return _message; } ++}; ++ ++typedef LinkedListDeque AsyncLogBuffer; ++ ++// ++// ASYNC LOGGING SUPPORT ++// ++// Summary: ++// Async Logging is working on the basis of singleton AsyncLogWriter, which manages an intermediate buffer and a flushing thread. ++// ++// Interface: ++// ++// initialize() is called once when JVM is initialized. It creates and initializes the singleton instance of AsyncLogWriter. ++// Once async logging is established, there's no way to turn it off. ++// ++// instance() is MT-safe and returns the pointer of the singleton instance if and only if async logging is enabled and has well ++// initialized. Clients can use its return value to determine async logging is established or not. ++// ++// The basic operation of AsyncLogWriter is enqueue(). 2 overloading versions of it are provided to match LogOutput::write(). ++// They are both MT-safe and non-blocking. Derived classes of LogOutput can invoke the corresponding enqueue() in write() and ++// return 0. AsyncLogWriter is responsible of copying neccessary data. ++// ++// The static member function flush() is designated to flush out all pending messages when JVM is terminating. ++// In normal JVM termination, flush() is invoked in LogConfiguration::finalize(). flush() is MT-safe and can be invoked arbitrary ++// times. It is no-op if async logging is not established. ++// ++class AsyncLogWriter : public NamedThread { ++ class AsyncLogLocker; ++ ++ static AsyncLogWriter* _instance; ++ // _lock(1) denotes a critional region. ++ Semaphore _lock; ++ // _sem is a semaphore whose value denotes how many messages have been enqueued. ++ // It decreases in AsyncLogWriter::run() ++ Semaphore _sem; ++ // A lock of IO ++ Semaphore _io_sem; ++ ++ volatile bool _initialized; ++ AsyncLogBuffer _buffer; ++ ++ const size_t _buffer_max_size; ++ ++ AsyncLogWriter(); ++ void enqueue_locked(const AsyncLogMessage& msg); ++ void write(); ++ void run(); ++ ++ public: ++ void enqueue(const char* msg); ++ ++ static AsyncLogWriter* instance(); ++ static void initialize(); ++ static void flush(); ++ // Printing ++ void print_on(outputStream* st) const; ++ ++}; ++ ++#endif // SHARE_LOGGING_LOGASYNCWRITER_HPP +diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp +index acc57f4..5f41e96 100644 +--- a/hotspot/src/share/vm/runtime/os.hpp ++++ b/hotspot/src/share/vm/runtime/os.hpp +@@ -463,6 +463,7 @@ class os: AllStatic { + java_thread, + compiler_thread, + watcher_thread, ++ asynclog_thread, // dedicated to flushing logs + os_thread + }; + +diff --git a/hotspot/src/share/vm/runtime/thread.cpp b/hotspot/src/share/vm/runtime/thread.cpp +index cacab59..61627e4 100644 +--- a/hotspot/src/share/vm/runtime/thread.cpp ++++ b/hotspot/src/share/vm/runtime/thread.cpp +@@ -57,6 +57,7 @@ + #include "runtime/java.hpp" + #include "runtime/javaCalls.hpp" + #include "runtime/jniPeriodicChecker.hpp" ++#include "runtime/logAsyncWriter.hpp" + #include "runtime/memprofiler.hpp" + #include "runtime/mutexLocker.hpp" + #include "runtime/objectMonitor.hpp" +@@ -881,7 +882,9 @@ void Thread::print_on_error(outputStream* st, char* buf, int buflen) const { + else if (is_GC_task_thread()) st->print("GCTaskThread"); + else if (is_Watcher_thread()) st->print("WatcherThread"); + else if (is_ConcurrentGC_thread()) st->print("ConcurrentGCThread"); +- else st->print("Thread"); ++ else if (this == AsyncLogWriter::instance()) { ++ st->print("%s", this->name()); ++ } else st->print("Thread"); + + st->print(" [stack: " PTR_FORMAT "," PTR_FORMAT "]", + _stack_base - _stack_size, _stack_base); +@@ -4387,6 +4390,12 @@ void Threads::print_on(outputStream* st, bool print_stacks, bool internal_format + st->cr(); + } + CompileBroker::print_compiler_threads_on(st); ++ if (UseAsyncGCLog) { ++ AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); ++ if (aio_writer != NULL) { ++ aio_writer->print_on(st); ++ } ++ } + st->flush(); + } + +@@ -4432,6 +4441,21 @@ void Threads::print_on_error(outputStream* st, Thread* current, char* buf, int b + wt->print_on_error(st, buf, buflen); + st->cr(); + } ++ ++ if (UseAsyncGCLog) { ++ AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); ++ if (aio_writer != NULL) { ++ bool is_current = (current == aio_writer); ++ found_current = found_current || is_current; ++ st->print("%s", is_current ? "=>" : " "); ++ ++ st->print(PTR_FORMAT, aio_writer); ++ st->print(" "); ++ aio_writer->print_on_error(st, buf, buflen); ++ st->cr(); ++ } ++ } ++ + if (!found_current) { + st->cr(); + st->print("=>" PTR_FORMAT " (exited) ", current); +diff --git a/hotspot/src/share/vm/runtime/vmStructs.cpp b/hotspot/src/share/vm/runtime/vmStructs.cpp +index ab20f5c..5d1cf2b 100644 +--- a/hotspot/src/share/vm/runtime/vmStructs.cpp ++++ b/hotspot/src/share/vm/runtime/vmStructs.cpp +@@ -97,6 +97,7 @@ + #include "runtime/sharedRuntime.hpp" + #include "runtime/stubRoutines.hpp" + #include "runtime/thread.inline.hpp" ++#include "runtime/logAsyncWriter.hpp" + #include "runtime/virtualspace.hpp" + #include "runtime/vmStructs.hpp" + #include "utilities/array.hpp" +@@ -1599,6 +1600,7 @@ typedef TwoOopHashtable SymbolTwoOopHashtable; + declare_type(Thread, ThreadShadow) \ + declare_type(NamedThread, Thread) \ + declare_type(WatcherThread, Thread) \ ++ declare_type(AsyncLogWriter, Thread) \ + declare_type(JavaThread, Thread) \ + declare_type(JvmtiAgentThread, JavaThread) \ + declare_type(ServiceThread, JavaThread) \ +diff --git a/hotspot/src/share/vm/utilities/linkedlist.hpp b/hotspot/src/share/vm/utilities/linkedlist.hpp +index a76c15c..f4f2a9b 100644 +--- a/hotspot/src/share/vm/utilities/linkedlist.hpp ++++ b/hotspot/src/share/vm/utilities/linkedlist.hpp +@@ -40,6 +40,25 @@ template class LinkedListNode : public ResourceObj { + E _data; // embedded content + LinkedListNode* _next; // next entry + ++ // Select member function 'bool U::equals(const U&) const' if 'U' is of class ++ // type. This works because of the "Substitution Failure Is Not An Error" ++ // (SFINAE) rule. Notice that this version of 'equal' will also be chosen for ++ // class types which don't define a corresponding 'equals()' method (and will ++ // result in a compilation error for them). It is not easily possible to ++ // specialize this 'equal()' function exclusively for class types which define ++ // the correct 'equals()' function because that function can be in a base ++ // class, a dependent base class or have a compatible but slightly different ++ // signature. ++ template ++ static bool equal(const U& a, const U& b, bool (U::*t)(const U&) const) { ++ return a.equals(b); ++ } ++ ++ template ++ static bool equal(const U& a, const U& b, ...) { ++ return a == b; ++ } ++ + protected: + LinkedListNode() : _next(NULL) { } + +@@ -51,6 +70,10 @@ template class LinkedListNode : public ResourceObj { + + E* data() { return &_data; } + const E* peek() const { return &_data; } ++ ++ bool equals(const E& t) const { ++ return equal(_data, t, NULL); ++ } + }; + + // A linked list interface. It does not specify +@@ -62,6 +85,7 @@ template class LinkedList : public ResourceObj { + + public: + LinkedList() : _head(NULL) { } ++ virtual ~LinkedList() {} + + inline void set_head(LinkedListNode* h) { _head = h; } + inline LinkedListNode* head() const { return _head; } +@@ -182,7 +206,7 @@ template * find_node(const E& e) { + LinkedListNode* p = this->head(); +- while (p != NULL && !p->peek()->equals(e)) { ++ while (p != NULL && !p->equals(e)) { + p = p->next(); + } + return p; +@@ -229,7 +253,7 @@ template * prev = NULL; + + while (tmp != NULL) { +- if (tmp->peek()->equals(e)) { ++ if (tmp->equals(e)) { + return remove_after(prev); + } + prev = tmp; +@@ -396,16 +420,21 @@ template class LinkedListIterator : public StackObj { + private: +- LinkedListNode* _p; +- bool _is_empty; ++ mutable LinkedListNode* _p; ++ + public: +- LinkedListIterator(LinkedListNode* head) : _p(head) { +- _is_empty = (head == NULL); +- } ++ LinkedListIterator(LinkedListNode* head) : _p(head) { } ++ ++ bool is_empty() const { return _p == NULL; } + +- bool is_empty() const { return _is_empty; } ++ E* next() { ++ if (_p == NULL) return NULL; ++ E* e = _p->data(); ++ _p = _p->next(); ++ return e; ++ } + +- const E* next() { ++ const E* next() const { + if (_p == NULL) return NULL; + const E* e = _p->peek(); + _p = _p->next(); +diff --git a/hotspot/src/share/vm/utilities/ostream.cpp b/hotspot/src/share/vm/utilities/ostream.cpp +index 14d82ad..5d40559 100644 +--- a/hotspot/src/share/vm/utilities/ostream.cpp ++++ b/hotspot/src/share/vm/utilities/ostream.cpp +@@ -30,6 +30,7 @@ + #include "runtime/mutexLocker.hpp" + #include "runtime/os.hpp" + #include "runtime/vmThread.hpp" ++#include "runtime/logAsyncWriter.hpp" + #include "utilities/defaultStream.hpp" + #include "utilities/ostream.hpp" + #include "utilities/top.hpp" +@@ -876,6 +877,17 @@ gcLogFileStream::gcLogFileStream(const char* file_name) : _file_lock(NULL) { + } + + void gcLogFileStream::write(const char* s, size_t len) { ++ if (UseAsyncGCLog) { ++ AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); ++ if (aio_writer != NULL) { ++ aio_writer->enqueue(s); ++ return; ++ } ++ } ++ write_blocking(s, len); ++} ++ ++void gcLogFileStream::write_blocking(const char* s, size_t len) { + if (_file != NULL) { + // we can't use Thread::current() here because thread may be NULL + // in early stage(ostream_init_log) +@@ -1047,6 +1059,17 @@ void gcLogFileStream::rotate_log_impl(bool force, outputStream* out) { + } + } + ++void gcLogFileStream::flush() { ++ if (UseAsyncGCLog) { ++ AsyncLogWriter* aio_writer = AsyncLogWriter::instance(); ++ if (aio_writer != NULL) { ++ // do nothing ++ return; ++ } ++ } ++ fileStream::flush(); ++} ++ + defaultStream* defaultStream::instance = NULL; + int defaultStream::_output_fd = 1; + int defaultStream::_error_fd = 2; +@@ -1456,6 +1479,9 @@ void ostream_exit() { + + // ostream_abort() is called by os::abort() when VM is about to die. + void ostream_abort() { ++ if (UseAsyncGCLog) { ++ AsyncLogWriter::flush(); ++ } + // Here we can't delete gclog_or_tty and tty, just flush their output + if (gclog_or_tty) gclog_or_tty->flush(); + if (tty) tty->flush(); +diff --git a/hotspot/src/share/vm/utilities/ostream.hpp b/hotspot/src/share/vm/utilities/ostream.hpp +index d0f9aac..85ff599 100644 +--- a/hotspot/src/share/vm/utilities/ostream.hpp ++++ b/hotspot/src/share/vm/utilities/ostream.hpp +@@ -254,6 +254,7 @@ class gcLogFileStream : public fileStream { + gcLogFileStream(const char* file_name); + ~gcLogFileStream(); + virtual void write(const char* c, size_t len); ++ void write_blocking(const char* c, size_t len); + virtual void rotate_log(bool force, outputStream* out = NULL); + void dump_loggc_header(); + +@@ -263,6 +264,8 @@ class gcLogFileStream : public fileStream { + ((GCLogFileSize != 0) && ((uintx)_bytes_written >= GCLogFileSize)); + } + ++ virtual void flush(); ++ + }; + + #ifndef PRODUCT +-- +1.8.3.1 diff --git a/8232069-enable-shutdown-UseCompressedClassPointers-U.patch b/8232069-enable-shutdown-UseCompressedClassPointers-U.patch new file mode 100644 index 0000000..243fa73 --- /dev/null +++ b/8232069-enable-shutdown-UseCompressedClassPointers-U.patch @@ -0,0 +1,594 @@ +From bf7e5b40eab65acf8988a30c1530654db1f8cf07 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Fri, 30 Sep 2022 17:18:50 +0800 +Subject: [PATCH 27/33] I68TO2: 8232069: enable shutdown UseCompressedClassPointers && + UseCompressedOops when CDS +--- + common/bin/compare.sh | 2 +- + hotspot/src/share/vm/memory/filemap.cpp | 12 ++ + hotspot/src/share/vm/memory/filemap.hpp | 4 + + hotspot/src/share/vm/memory/metaspace.cpp | 42 +++-- + hotspot/src/share/vm/runtime/arguments.cpp | 47 ++--- + hotspot/src/share/vm/runtime/arguments.hpp | 2 +- + .../CDSCompressedKPtrsError.java | 93 ---------- + .../appcds/CommandLineFlagComboNegative.java | 5 +- + .../appcds/TestCombinedCompressedFlags.java | 192 +++++++++++++++++++++ + jdk/make/BuildJdk.gmk | 2 + + 10 files changed, 253 insertions(+), 148 deletions(-) + delete mode 100644 hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java + create mode 100644 hotspot/test/runtime/appcds/TestCombinedCompressedFlags.java + +diff --git a/common/bin/compare.sh b/common/bin/compare.sh +index a36464a..e6a3f67 100644 +--- a/common/bin/compare.sh ++++ b/common/bin/compare.sh +@@ -290,7 +290,7 @@ compare_general_files() { + ! -name "ct.sym" ! -name "*.diz" ! -name "*.dll" \ + ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \ + ! -name "*.lib" ! -name "*.war" ! -name "JavaControlPanel" \ +- ! -name "classes.jsa" \ ++ ! -name "classes.jsa" | -name "classes_nocoops.jsa" \ + | $GREP -v "./bin/" | $SORT | $FILTER) + + echo General files... +diff --git a/hotspot/src/share/vm/memory/filemap.cpp b/hotspot/src/share/vm/memory/filemap.cpp +index 0682cd6..0d21707 100644 +--- a/hotspot/src/share/vm/memory/filemap.cpp ++++ b/hotspot/src/share/vm/memory/filemap.cpp +@@ -241,6 +241,8 @@ void FileMapInfo::FileMapHeader::populate(FileMapInfo* mapinfo, size_t alignment + _alignment = alignment; + _obj_alignment = ObjectAlignmentInBytes; + ++ _compressed_oops = UseCompressedOops; ++ _compressed_class_ptrs = UseCompressedClassPointers; + if (!DynamicDumpSharedSpaces) { + _classpath_entry_table_size = mapinfo->_classpath_entry_table_size; + _classpath_entry_table = mapinfo->_classpath_entry_table; +@@ -987,6 +989,16 @@ bool FileMapInfo::FileMapHeader::validate() { + _obj_alignment, ObjectAlignmentInBytes); + return false; + } ++ if (PrintSharedSpaces) { ++ tty->print_cr("Archive was created with UseCompressedOops = %d, UseCompressedClassPointers = %d", ++ compressed_oops(), compressed_class_pointers()); ++ } ++ ++ if (compressed_oops() != UseCompressedOops || compressed_class_pointers() != UseCompressedClassPointers) { ++ FileMapInfo::fail_continue("Unable to use shared archive.\nThe saved state of UseCompressedOops and UseCompressedClassPointers is " ++ "different from runtime, CDS will be disabled."); ++ return false; ++ } + + return true; + } +diff --git a/hotspot/src/share/vm/memory/filemap.hpp b/hotspot/src/share/vm/memory/filemap.hpp +index 27fff35..debfb50 100644 +--- a/hotspot/src/share/vm/memory/filemap.hpp ++++ b/hotspot/src/share/vm/memory/filemap.hpp +@@ -105,6 +105,8 @@ public: + size_t _alignment; // how shared archive should be aligned + int _obj_alignment; // value of ObjectAlignmentInBytes + bool _is_default_jsa; // indicates whether is the default jsa file ++ bool _compressed_oops; // save the flag UseCompressedOops ++ bool _compressed_class_ptrs; // save the flag UseCompressedClassPointers + + struct space_info { + int _crc; // crc checksum of the current space +@@ -156,6 +158,8 @@ public: + int compute_crc(); + unsigned int magic() const { return _magic; } + const char* jvm_ident() const { return _jvm_ident; } ++ bool compressed_oops() const { return _compressed_oops; } ++ bool compressed_class_pointers() const { return _compressed_class_ptrs; } + }; + + // Fixme +diff --git a/hotspot/src/share/vm/memory/metaspace.cpp b/hotspot/src/share/vm/memory/metaspace.cpp +index cf4a112..07bc47a 100644 +--- a/hotspot/src/share/vm/memory/metaspace.cpp ++++ b/hotspot/src/share/vm/memory/metaspace.cpp +@@ -3634,25 +3634,33 @@ void Metaspace::global_initialize() { + } + + #ifdef _LP64 +- if (cds_total + compressed_class_space_size() > UnscaledClassSpaceMax) { +- vm_exit_during_initialization("Unable to dump shared archive.", +- err_msg("Size of archive (" SIZE_FORMAT ") + compressed class space (" +- SIZE_FORMAT ") == total (" SIZE_FORMAT ") is larger than compressed " +- "klass limit: " SIZE_FORMAT, cds_total, compressed_class_space_size(), +- cds_total + compressed_class_space_size(), UnscaledClassSpaceMax)); +- } ++ if (UseCompressedClassPointers) { ++ if (cds_total + compressed_class_space_size() > UnscaledClassSpaceMax) { ++ vm_exit_during_initialization("Unable to dump shared archive.", ++ err_msg("Size of archive (" SIZE_FORMAT ") + compressed class space (" ++ SIZE_FORMAT ") == total (" SIZE_FORMAT ") is larger than compressed " ++ "klass limit: " SIZE_FORMAT, cds_total, compressed_class_space_size(), ++ cds_total + compressed_class_space_size(), UnscaledClassSpaceMax)); ++ } + +- // Set the compressed klass pointer base so that decoding of these pointers works +- // properly when creating the shared archive. +- assert(UseCompressedOops && UseCompressedClassPointers, +- "UseCompressedOops and UseCompressedClassPointers must be set"); +- Universe::set_narrow_klass_base((address)_space_list->current_virtual_space()->bottom()); +- if (TraceMetavirtualspaceAllocation && Verbose) { +- gclog_or_tty->print_cr("Setting_narrow_klass_base to Address: " PTR_FORMAT, +- _space_list->current_virtual_space()->bottom()); +- } ++ // Set the compressed klass pointer base so that decoding of these pointers works ++ // properly when creating the shared archive. ++ assert(UseCompressedOops && UseCompressedClassPointers, ++ "UseCompressedOops and UseCompressedClassPointers must be set"); ++ Universe::set_narrow_klass_base((address)_space_list->current_virtual_space()->bottom()); ++ if (TraceMetavirtualspaceAllocation && Verbose) { ++ gclog_or_tty->print_cr("Setting_narrow_klass_base to Address: " PTR_FORMAT, ++ _space_list->current_virtual_space()->bottom()); ++ } + +- Universe::set_narrow_klass_shift(0); ++ Universe::set_narrow_klass_shift(0); ++ } else { ++ if (cds_total > UnscaledClassSpaceMax) { ++ vm_exit_during_initialization("Unable to dump shared archive.", ++ err_msg("Size of archive (" SIZE_FORMAT ") is larger than compressed " ++ "klass limit: " SIZE_FORMAT, cds_total, UnscaledClassSpaceMax)); ++ } ++ } + #endif // _LP64 + #endif // INCLUDE_CDS + } else { +diff --git a/hotspot/src/share/vm/runtime/arguments.cpp b/hotspot/src/share/vm/runtime/arguments.cpp +index fba3d4b..b0b5414 100644 +--- a/hotspot/src/share/vm/runtime/arguments.cpp ++++ b/hotspot/src/share/vm/runtime/arguments.cpp +@@ -242,7 +242,9 @@ bool Arguments::init_shared_archive_paths() { + } + } + +- if (SharedArchiveFile != NULL) { ++ if (SharedArchiveFile == NULL) { ++ SharedArchivePath = get_default_shared_archive_path(); ++ } else { + int archives = num_archives(SharedArchiveFile); + if (is_dumping_archive()) { + if (archives > 1) { +@@ -4008,7 +4010,7 @@ jint Arguments::parse_options_environment_variable(const char* name, SysClassPat + return JNI_OK; + } + +-void Arguments::set_shared_spaces_flags() { ++jint Arguments::set_shared_spaces_flags() { + if (DumpSharedSpaces) { + if (FailOverToOldVerifier) { + // Don't fall back to the old verifier on verification failure. If a +@@ -4022,22 +4024,16 @@ void Arguments::set_shared_spaces_flags() { + warning("cannot dump shared archive while using shared archive"); + } + UseSharedSpaces = false; +-#ifdef _LP64 +- if (!UseCompressedOops || !UseCompressedClassPointers) { +- vm_exit_during_initialization( +- "Cannot dump shared archive when UseCompressedOops or UseCompressedClassPointers is off.", NULL); +- } +- } else { +- if (!UseCompressedOops || !UseCompressedClassPointers) { +- no_shared_spaces("UseCompressedOops and UseCompressedClassPointers must be on for UseSharedSpaces."); +- } +-#endif + } + + #if INCLUDE_CDS + // Initialize shared archive paths which could include both base and dynamic archive paths +- init_shared_archive_paths(); ++ // This must be after set_ergonomics_flags() called so flag UseCompressedOops is set properly. ++ if(!init_shared_archive_paths()) { ++ return JNI_ENOMEM; ++ } + #endif // INCLUDE_CDS ++ return JNI_OK; + } + + #if !INCLUDE_ALL_GCS +@@ -4065,25 +4061,14 @@ char* Arguments::get_default_shared_archive_path() { + const size_t len = jvm_path_len + file_sep_len + 20; + default_archive_path = NEW_C_HEAP_ARRAY(char, len, mtInternal); + if (default_archive_path != NULL) { +- jio_snprintf(default_archive_path, len, "%s%sclasses.jsa", ++ jio_snprintf(default_archive_path, len, ++ UseCompressedClassPointers ? "%s%sclasses.jsa" : "%s%sclasses_nocoops.jsa", + jvm_path, os::file_separator()); + } + Arguments::set_is_default_jsa(true); + return default_archive_path; + } + +-// Sharing support +-// Construct the path to the archive +-static char* get_shared_archive_path() { +- char *shared_archive_path; +- if (SharedArchiveFile == NULL) { +- shared_archive_path = Arguments::get_default_shared_archive_path(); +- } else { +- shared_archive_path = os::strdup(SharedArchiveFile, mtInternal); +- } +- return shared_archive_path; +-} +- + + #ifndef PRODUCT + // Determine whether LogVMOutput should be implicitly turned on. +@@ -4221,13 +4206,6 @@ jint Arguments::parse(const JavaVMInitArgs* args) { + return result; + } + +- // Call get_shared_archive_path() here, after possible SharedArchiveFile option got parsed. +- SharedArchivePath = get_shared_archive_path(); +- if (SharedArchivePath == NULL) { +- return JNI_ENOMEM; +- } +- +- + // Set up VerifySharedSpaces + if (FLAG_IS_DEFAULT(VerifySharedSpaces) && SharedArchiveFile != NULL) { + VerifySharedSpaces = true; +@@ -4321,7 +4299,8 @@ jint Arguments::apply_ergo() { + // Set flags based on ergonomics. + set_ergonomics_flags(); + +- set_shared_spaces_flags(); ++ jint result = set_shared_spaces_flags(); ++ if (result != JNI_OK) return result; + + #if defined(SPARC) + // BIS instructions require 'membar' instruction regardless of the number +diff --git a/hotspot/src/share/vm/runtime/arguments.hpp b/hotspot/src/share/vm/runtime/arguments.hpp +index 65907eb..88741e8 100644 +--- a/hotspot/src/share/vm/runtime/arguments.hpp ++++ b/hotspot/src/share/vm/runtime/arguments.hpp +@@ -343,7 +343,7 @@ class Arguments : AllStatic { + static void set_use_compressed_klass_ptrs(); + static void select_gc(); + static void set_ergonomics_flags(); +- static void set_shared_spaces_flags(); ++ static jint set_shared_spaces_flags(); + // limits the given memory size by the maximum amount of memory this process is + // currently allowed to allocate or reserve. + static julong limit_by_allocatable_memory(julong size); +diff --git a/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java b/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java +deleted file mode 100644 +index 05b4ac9..0000000 +--- a/hotspot/test/runtime/CDSCompressedKPtrs/CDSCompressedKPtrsError.java ++++ /dev/null +@@ -1,93 +0,0 @@ +-/* +- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. +- * 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 8003424 +- * @summary Test that cannot use CDS if UseCompressedClassPointers is turned off. +- * @library /testlibrary +- * @run main CDSCompressedKPtrsError +- */ +- +-import com.oracle.java.testlibrary.*; +- +-public class CDSCompressedKPtrsError { +- public static void main(String[] args) throws Exception { +- ProcessBuilder pb; +- if (Platform.is64bit()) { +- pb = ProcessTools.createJavaProcessBuilder( +- "-XX:+UseCompressedOops", "-XX:+UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", +- "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); +- OutputAnalyzer output = new OutputAnalyzer(pb.start()); +- try { +- output.shouldContain("Loading classes to share"); +- output.shouldHaveExitValue(0); +- +- pb = ProcessTools.createJavaProcessBuilder( +- "-XX:-UseCompressedClassPointers", "-XX:-UseCompressedOops", +- "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); +- output = new OutputAnalyzer(pb.start()); +- output.shouldContain("Unable to use shared archive"); +- output.shouldHaveExitValue(0); +- +- pb = ProcessTools.createJavaProcessBuilder( +- "-XX:-UseCompressedClassPointers", "-XX:+UseCompressedOops", +- "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); +- output = new OutputAnalyzer(pb.start()); +- output.shouldContain("Unable to use shared archive"); +- output.shouldHaveExitValue(0); +- +- pb = ProcessTools.createJavaProcessBuilder( +- "-XX:+UseCompressedClassPointers", "-XX:-UseCompressedOops", +- "-XX:+UnlockDiagnosticVMOptions", "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:on", "-version"); +- output = new OutputAnalyzer(pb.start()); +- output.shouldContain("Unable to use shared archive"); +- output.shouldHaveExitValue(0); +- +- } catch (RuntimeException e) { +- output.shouldContain("Unable to use shared archive"); +- output.shouldHaveExitValue(1); +- } +- +- // Test bad options with -Xshare:dump. +- pb = ProcessTools.createJavaProcessBuilder( +- "-XX:-UseCompressedOops", "-XX:+UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", +- "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); +- output = new OutputAnalyzer(pb.start()); +- output.shouldContain("Cannot dump shared archive"); +- +- pb = ProcessTools.createJavaProcessBuilder( +- "-XX:+UseCompressedOops", "-XX:-UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", +- "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); +- output = new OutputAnalyzer(pb.start()); +- output.shouldContain("Cannot dump shared archive"); +- +- pb = ProcessTools.createJavaProcessBuilder( +- "-XX:-UseCompressedOops", "-XX:-UseCompressedClassPointers", "-XX:+UnlockDiagnosticVMOptions", +- "-XX:SharedArchiveFile=./sample.jsa", "-Xshare:dump"); +- output = new OutputAnalyzer(pb.start()); +- output.shouldContain("Cannot dump shared archive"); +- +- } +- } +-} +diff --git a/hotspot/test/runtime/appcds/CommandLineFlagComboNegative.java b/hotspot/test/runtime/appcds/CommandLineFlagComboNegative.java +index 4fb965a..286893e 100644 +--- a/hotspot/test/runtime/appcds/CommandLineFlagComboNegative.java ++++ b/hotspot/test/runtime/appcds/CommandLineFlagComboNegative.java +@@ -1,5 +1,6 @@ + /* + * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -64,9 +65,9 @@ public class CommandLineFlagComboNegative { + testTable.add( new TestVector("-XX:ObjectAlignmentInBytes=64", "-XX:ObjectAlignmentInBytes=32", + "An error has occurred while processing the shared archive file", 1) ); + testTable.add( new TestVector("-XX:+UseCompressedOops", "-XX:-UseCompressedOops", +- "Class data sharing is inconsistent with other specified options", 1) ); ++ "The saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime, CDS will be disabled", 1) ); + testTable.add( new TestVector("-XX:+UseCompressedClassPointers", "-XX:-UseCompressedClassPointers", +- "Class data sharing is inconsistent with other specified options", 1) ); ++ "The saved state of UseCompressedOops and UseCompressedClassPointers is different from runtime, CDS will be disabled", 1) ); + } + } + +diff --git a/hotspot/test/runtime/appcds/TestCombinedCompressedFlags.java b/hotspot/test/runtime/appcds/TestCombinedCompressedFlags.java +new file mode 100644 +index 0000000..6f0a3be +--- /dev/null ++++ b/hotspot/test/runtime/appcds/TestCombinedCompressedFlags.java +@@ -0,0 +1,192 @@ ++/* ++ * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * 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 8232069 ++ * @summary Testing different combination of CompressedOops and CompressedClassPointers ++ * @requires (vm.gc=="null") ++ * @library /testlibrary ++ * @compile test-classes/Hello.java ++ * @run main/othervm TestCombinedCompressedFlags ++ */ ++ ++import com.oracle.java.testlibrary.Platform; ++import com.oracle.java.testlibrary.OutputAnalyzer; ++import java.util.List; ++import java.util.ArrayList; ++ ++public class TestCombinedCompressedFlags { ++ public static String HELLO_STRING = "Hello World"; ++ public static String EXEC_ABNORMAL_MSG = "Unable to use shared archive."; ++ public static final int PASS = 0; ++ public static final int FAIL = 1; ++ ++ static class ConfArg { ++ public boolean useCompressedOops; // UseCompressedOops ++ public boolean useCompressedClassPointers; // UseCompressedClassPointers ++ public String msg; ++ public int code; ++ public ConfArg(boolean useCompressedOops, boolean useCompressedClassPointers, String msg, int code) { ++ this.useCompressedOops = useCompressedOops; ++ this.useCompressedClassPointers = useCompressedClassPointers; ++ this.msg = msg; ++ this.code = code; ++ } ++ } ++ ++ static class RunArg { ++ public ConfArg dumpArg; ++ public List execArgs; ++ public RunArg(ConfArg arg) { ++ dumpArg = arg; ++ initExecArgs(); ++ } ++ private void initExecArgs() { ++ /* The combinations have four cases. Note COOP off, CCPTR must be off ++ * UseCompressedOops UseCompressedClassPointers Result ++ * 1. ++ * dump: on on ++ * test: on on Pass ++ * on off Fail ++ * off on Fail ++ * off off Fail ++ * 2. ++ * dump: on off ++ * test: on off Pass ++ * on on Fail ++ * off on Pass ++ * off off Fail ++ * 3. ++ * dump: off on ++ * test: off on Pass ++ * off off Pass ++ * on on Fail ++ * on off Fail ++ * 4. ++ * dump: off off ++ * test: off off Pass ++ * off on Pass ++ * on on Fail ++ * on off Fail ++ **/ ++ execArgs = new ArrayList(); ++ if (dumpArg.useCompressedOops && dumpArg.useCompressedClassPointers) { ++ execArgs ++ .add(new ConfArg(true, true, HELLO_STRING, PASS)); ++ execArgs ++ .add(new ConfArg(true, false, EXEC_ABNORMAL_MSG, FAIL)); ++ execArgs ++ .add(new ConfArg(false, true, EXEC_ABNORMAL_MSG, FAIL)); ++ execArgs ++ .add(new ConfArg(false, false, EXEC_ABNORMAL_MSG, FAIL)); ++ ++ } else if(dumpArg.useCompressedOops && !dumpArg.useCompressedClassPointers) { ++ execArgs ++ .add(new ConfArg(true, false, HELLO_STRING, PASS)); ++ execArgs ++ .add(new ConfArg(true, true, EXEC_ABNORMAL_MSG, FAIL)); ++ execArgs ++ .add(new ConfArg(false, true, EXEC_ABNORMAL_MSG, FAIL)); ++ execArgs ++ .add(new ConfArg(false, false, EXEC_ABNORMAL_MSG, FAIL)); ++ ++ } else if (!dumpArg.useCompressedOops && dumpArg.useCompressedClassPointers) { ++ execArgs ++ .add(new ConfArg(false, false, HELLO_STRING, PASS)); ++ execArgs ++ .add(new ConfArg(false, true, HELLO_STRING, PASS)); ++ execArgs ++ .add(new ConfArg(true, true, EXEC_ABNORMAL_MSG, FAIL)); ++ execArgs ++ .add(new ConfArg(true, false, EXEC_ABNORMAL_MSG, FAIL)); ++ } else if (!dumpArg.useCompressedOops && !dumpArg.useCompressedClassPointers) { ++ execArgs ++ .add(new ConfArg(false, false, HELLO_STRING, PASS)); ++ execArgs ++ .add(new ConfArg(false, true, HELLO_STRING, PASS)); ++ execArgs ++ .add(new ConfArg(true, true, EXEC_ABNORMAL_MSG, FAIL)); ++ execArgs ++ .add(new ConfArg(true, false, EXEC_ABNORMAL_MSG, FAIL)); ++ } ++ } ++ } ++ ++ public static String getCompressedOopsArg(boolean on) { ++ if (on) return "-XX:+UseCompressedOops"; ++ else return "-XX:-UseCompressedOops"; ++ } ++ ++ public static String getCompressedClassPointersArg(boolean on) { ++ if (on) return "-XX:+UseCompressedClassPointers"; ++ else return "-XX:-UseCompressedClassPointers"; ++ } ++ ++ public static List runList; ++ ++ public static void configureRunArgs() { ++ runList = new ArrayList(); ++ runList ++ .add(new RunArg(new ConfArg(true, true, null, PASS))); ++ runList ++ .add(new RunArg(new ConfArg(true, false, null, PASS))); ++ runList ++ .add(new RunArg(new ConfArg(false, true, null, PASS))); ++ runList ++ .add(new RunArg(new ConfArg(false, false, null, PASS))); ++ } ++ ++ public static void main(String[] args) throws Exception { ++ if (!Platform.is64bit()) { ++ System.out.println("Test case not applicable on 32-bit platforms"); ++ return; ++ ++ } ++ ++ String helloJar = JarBuilder.build("hello", "Hello"); ++ configureRunArgs(); ++ OutputAnalyzer out; ++ for (RunArg t: runList) { ++ out = TestCommon ++ .dump(helloJar, ++ new String[] {"Hello"}, ++ getCompressedOopsArg(t.dumpArg.useCompressedOops), ++ getCompressedClassPointersArg(t.dumpArg.useCompressedClassPointers)); ++ out.shouldContain("total : "); ++ out.shouldHaveExitValue(0); ++ ++ for (ConfArg c : t.execArgs) { ++ out = TestCommon.exec(helloJar, ++ "-cp", ++ helloJar, ++ getCompressedOopsArg(c.useCompressedOops), ++ getCompressedClassPointersArg(c.useCompressedClassPointers), ++ "Hello"); ++ out.shouldContain(c.msg); ++ out.shouldHaveExitValue(c.code); ++ } ++ } ++ } ++} +diff --git a/jdk/make/BuildJdk.gmk b/jdk/make/BuildJdk.gmk +index bb8ea8a..6707456 100644 +--- a/jdk/make/BuildJdk.gmk ++++ b/jdk/make/BuildJdk.gmk +@@ -106,8 +106,10 @@ images: + ifeq ($(BUILD_CDS_ARCHIVE), true) + echo Creating CDS archive for jdk image + $(JDK_IMAGE_DIR)/bin/java -Xshare:dump -Xmx128M -Xms128M -XX:ParallelGCThreads=1 -Xint $(LOG_INFO) ++ $(JDK_IMAGE_DIR)/bin/java -Xshare:dump -Xmx128M -Xms128M -XX:ParallelGCThreads=1 -Xint -XX:-UseCompressedOops $(LOG_INFO) + echo Creating CDS archive for jre image + $(JRE_IMAGE_DIR)/bin/java -Xshare:dump -Xmx128M -Xms128M -XX:ParallelGCThreads=1 -Xint $(LOG_INFO) ++ $(JDK_IMAGE_DIR)/bin/java -Xshare:dump -Xmx128M -Xms128M -XX:ParallelGCThreads=1 -Xint -XX:-UseCompressedOops $(LOG_INFO) + endif + + +-- +1.8.3.1 diff --git a/8242181-Show-source-information-when-printing-native.patch b/8242181-Show-source-information-when-printing-native.patch new file mode 100644 index 0000000..ca02b21 --- /dev/null +++ b/8242181-Show-source-information-when-printing-native.patch @@ -0,0 +1,2830 @@ +From 24dedc988ac599b3191f6a69c1bce35fcc6bf748 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Thu, 15 Dec 2022 20:05:20 +0800 +Subject: [PATCH 23/33] I68TO2: 8242181: Show source information when printing native + stack traces in hs_err files +--- + hotspot/src/share/vm/runtime/globals.hpp | 3 + + hotspot/src/share/vm/utilities/debug.cpp | 9 + + hotspot/src/share/vm/utilities/decoder.cpp | 9 + + hotspot/src/share/vm/utilities/decoder.hpp | 17 + + hotspot/src/share/vm/utilities/decoder_elf.cpp | 39 + + hotspot/src/share/vm/utilities/decoder_elf.hpp | 2 + + hotspot/src/share/vm/utilities/elfFile.cpp | 1510 +++++++++++++++++++- + hotspot/src/share/vm/utilities/elfFile.hpp | 732 +++++++++- + hotspot/src/share/vm/utilities/nativeCallStack.cpp | 11 +- + hotspot/src/share/vm/utilities/vmError.cpp | 6 + + hotspot/src/share/vm/utilities/vmError.hpp | 3 + + jdk/test/jdk/java/dwarf/TestDwarf.java | 240 ++++ + 12 files changed, 2563 insertions(+), 18 deletions(-) + create mode 100644 jdk/test/jdk/java/dwarf/TestDwarf.java + +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 64d40e0..d1e3cda 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -546,6 +546,9 @@ class CommandLineFlags { + develop(bool, CleanChunkPoolAsync, falseInEmbedded, \ + "Clean the chunk pool asynchronously") \ + \ ++ develop(intx, TraceDwarfLevel, 0, \ ++ "Debug levels for the dwarf parser") \ ++ \ + /* Temporary: See 6948537 */ \ + experimental(bool, UseMemSetInBOT, true, \ + "(Unstable) uses memset in BOT updates in GC code") \ +diff --git a/hotspot/src/share/vm/utilities/debug.cpp b/hotspot/src/share/vm/utilities/debug.cpp +index 8cea16d..6a9310e 100644 +--- a/hotspot/src/share/vm/utilities/debug.cpp ++++ b/hotspot/src/share/vm/utilities/debug.cpp +@@ -51,6 +51,7 @@ + #include "utilities/events.hpp" + #include "utilities/top.hpp" + #include "utilities/vmError.hpp" ++#include "utilities/decoder.hpp" + #ifdef TARGET_OS_FAMILY_linux + # include "os_linux.inline.hpp" + #endif +@@ -751,7 +752,15 @@ void print_native_stack(outputStream* st, frame fr, Thread* t, char* buf, int bu + int count = 0; + while (count++ < StackPrintLimit) { + fr.print_on_error(st, buf, buf_size); ++ ++ char filename[128]; ++ int line_no; ++ if (Decoder::get_source_info(fr.pc(), filename, sizeof(filename), &line_no, count != 1)) { ++ st->print(" (%s:%d)", filename, line_no); ++ } ++ + st->cr(); ++ + // Compiled code may use EBP register on x86 so it looks like + // non-walkable C frame. Use frame.sender() for java frames. + if (t && t->is_Java_thread()) { +diff --git a/hotspot/src/share/vm/utilities/decoder.cpp b/hotspot/src/share/vm/utilities/decoder.cpp +index 7ed913a..ae58bf5 100644 +--- a/hotspot/src/share/vm/utilities/decoder.cpp ++++ b/hotspot/src/share/vm/utilities/decoder.cpp +@@ -143,6 +143,15 @@ bool Decoder::can_decode_C_frame_in_vm() { + return decoder->can_decode_C_frame_in_vm(); + } + ++bool Decoder::get_source_info(address pc, char* filename, size_t filename_len, int* line, bool is_pc_after_call) { ++ if (VMError::is_error_reported_in_current_thread()) { ++ return get_error_handler_instance()->get_source_info(pc, filename, filename_len, line, is_pc_after_call); ++ } else { ++ MutexLockerEx locker(shared_decoder_lock(), Mutex::_no_safepoint_check_flag); ++ return get_shared_instance()->get_source_info(pc, filename, filename_len, line, is_pc_after_call); ++ } ++} ++ + /* + * Shutdown shared decoder and replace it with + * _do_nothing_decoder. Do nothing with error handler +diff --git a/hotspot/src/share/vm/utilities/decoder.hpp b/hotspot/src/share/vm/utilities/decoder.hpp +index c6c09e3..e83b87f 100644 +--- a/hotspot/src/share/vm/utilities/decoder.hpp ++++ b/hotspot/src/share/vm/utilities/decoder.hpp +@@ -68,6 +68,11 @@ public: + return (status > 0); + } + ++ // Get filename and line number information. ++ virtual bool get_source_info(address pc, char* filename, size_t filename_len, int* line, bool is_pc_after_call) { ++ return false; ++ } ++ + protected: + decoder_status _decoder_status; + }; +@@ -97,6 +102,11 @@ public: + virtual bool can_decode_C_frame_in_vm() const { + return false; + } ++ ++ // Get filename and line number information. ++ virtual bool get_source_info(address pc, char* filename, size_t filename_len, int* line, bool is_pc_after_call) { ++ return false; ++ } + }; + + +@@ -107,6 +117,13 @@ public: + static bool demangle(const char* symbol, char* buf, int buflen); + static bool can_decode_C_frame_in_vm(); + ++ // Attempts to retrieve source file name and line number associated with a pc. ++ // If filename != NULL, points to a buffer of size filename_len which will receive the ++ // file name. File name will be silently truncated if output buffer is too small. ++ // If is_pc_after_call is true, then pc is treated as pointing to the next instruction ++ // after a call. The source information for the call instruction is fetched in that case. ++ static bool get_source_info(address pc, char* filename, size_t filename_len, int* line, bool is_pc_after_call = false); ++ + // shutdown shared instance + static void shutdown(); + protected: +diff --git a/hotspot/src/share/vm/utilities/decoder_elf.cpp b/hotspot/src/share/vm/utilities/decoder_elf.cpp +index 9730883..bb72ce1 100644 +--- a/hotspot/src/share/vm/utilities/decoder_elf.cpp ++++ b/hotspot/src/share/vm/utilities/decoder_elf.cpp +@@ -73,4 +73,43 @@ ElfFile* ElfDecoder::get_elf_file(const char* filepath) { + + return file; + } ++ ++bool ElfDecoder::get_source_info(address pc, char* filename, size_t filename_len, int* line, bool is_pc_after_call) { ++ assert(filename != NULL && filename_len > 0 && line != NULL, "Argument error"); ++ filename[0] = '\0'; ++ *line = -1; ++ ++ char filepath[JVM_MAXPATHLEN]; ++ filepath[JVM_MAXPATHLEN - 1] = '\0'; ++ int offset_in_library = -1; ++ if (!os::dll_address_to_library_name(pc, filepath, sizeof(filepath), &offset_in_library)) { ++ // Method not found. offset_in_library should not overflow. ++ DWARF_LOG_ERROR("Did not find library for address " INTPTR_FORMAT, p2i(pc)) ++ return false; ++ } ++ ++ if (filepath[JVM_MAXPATHLEN - 1] != '\0') { ++ DWARF_LOG_ERROR("File path is too large to fit into buffer of size %d", JVM_MAXPATHLEN); ++ return false; ++ } ++ ++ const uint32_t unsigned_offset_in_library = (uint32_t)offset_in_library; ++ ++ ElfFile* file = get_elf_file(filepath); ++ if (file == NULL) { ++ return false; ++ } ++ DWARF_LOG_INFO("##### Find filename and line number for offset " PTR32_FORMAT " in library %s #####", ++ unsigned_offset_in_library, filepath); ++ ++ if (!file->get_source_info(unsigned_offset_in_library, filename, filename_len, line, is_pc_after_call)) { ++ return false; ++ } ++ ++ DWARF_LOG_SUMMARY("pc: " INTPTR_FORMAT ", offset: " PTR32_FORMAT ", filename: %s, line: %u", ++ p2i(pc), offset_in_library, filename, *line); ++ DWARF_LOG_INFO("\n") // To structure the debug output better. ++ return true; ++} ++ + #endif // !_WINDOWS && !__APPLE__ +diff --git a/hotspot/src/share/vm/utilities/decoder_elf.hpp b/hotspot/src/share/vm/utilities/decoder_elf.hpp +index e92c958..5551f42 100644 +--- a/hotspot/src/share/vm/utilities/decoder_elf.hpp ++++ b/hotspot/src/share/vm/utilities/decoder_elf.hpp +@@ -48,6 +48,8 @@ public: + return false; + } + ++ bool get_source_info(address pc, char* buf, size_t buflen, int* line, bool is_pc_after_call); ++ + private: + ElfFile* get_elf_file(const char* filepath); + +diff --git a/hotspot/src/share/vm/utilities/elfFile.cpp b/hotspot/src/share/vm/utilities/elfFile.cpp +index ac943bd..81bd441 100644 +--- a/hotspot/src/share/vm/utilities/elfFile.cpp ++++ b/hotspot/src/share/vm/utilities/elfFile.cpp +@@ -32,12 +32,41 @@ + #include + + #include "memory/allocation.inline.hpp" ++#include "memory/resourceArea.hpp" + #include "utilities/decoder.hpp" + #include "utilities/elfFile.hpp" + #include "utilities/elfFuncDescTable.hpp" + #include "utilities/elfStringTable.hpp" + #include "utilities/elfSymbolTable.hpp" + ++const char* ElfFile::USR_LIB_DEBUG_DIRECTORY = "/usr/lib/debug"; ++ ++bool FileReader::read(void* buf, size_t size) { ++ assert(buf != NULL, "no buffer"); ++ assert(size > 0, "no space"); ++ return fread(buf, size, 1, _fd) == 1; ++} ++ ++size_t FileReader::read_buffer(void* buf, size_t size) { ++ assert(buf != NULL, "no buffer"); ++ assert(size > 0, "no space"); ++ return fread(buf, 1, size, _fd); ++} ++ ++bool FileReader::set_position(long offset) { ++ return fseek(_fd, offset, SEEK_SET) == 0; ++} ++ ++MarkedFileReader::MarkedFileReader(FILE* fd) : FileReader(fd) { ++ _marked_pos = ftell(fd); ++} ++ ++MarkedFileReader::~MarkedFileReader() { ++ if (_marked_pos != -1) { ++ set_position(_marked_pos); ++ } ++} ++ + + ElfFile::ElfFile(const char* filepath) { + assert(filepath, "null file path"); +@@ -47,6 +76,8 @@ ElfFile::ElfFile(const char* filepath) { + m_funcDesc_table = NULL; + m_next = NULL; + m_status = NullDecoder::no_error; ++ m_shdr_string_table = NULL; ++ m_dwarf_file = NULL; + + int len = strlen(filepath) + 1; + m_filepath = (const char*)os::malloc(len * sizeof(char), mtInternal); +@@ -83,6 +114,16 @@ ElfFile::~ElfFile() { + if (m_next != NULL) { + delete m_next; + } ++ ++ if (m_shdr_string_table != NULL) { ++ delete m_shdr_string_table; ++ } ++ ++ if (m_dwarf_file != NULL) { ++ delete m_dwarf_file; ++ m_dwarf_file = NULL; ++ } ++ + }; + + +@@ -128,7 +169,12 @@ bool ElfFile::load_tables() { + m_status = NullDecoder::out_of_memory; + return false; + } +- add_string_table(table); ++ if (index == m_elfHdr.e_shstrndx) { ++ assert(m_shdr_string_table == NULL, "Only set once"); ++ m_shdr_string_table = table; ++ } else { ++ add_string_table(table); ++ } + } else if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) { + // symbol tables + ElfSymbolTable* table = new (std::nothrow) ElfSymbolTable(m_file, shdr); +@@ -270,4 +316,1466 @@ bool ElfFile::specifies_noexecstack() { + } + #endif + ++bool ElfFile::get_source_info(const uint32_t offset_in_library, char* filename, const size_t filename_len, ++ int* line, bool is_pc_after_call) { ++ ResourceMark rm; ++ if (!load_dwarf_file()) { ++ // Some ELF libraries do not provide separate .debuginfo files. Check if the current ELF file has the required ++ // DWARF sections. If so, treat the current ELF file as DWARF file. ++ if (!is_valid_dwarf_file()) { ++ DWARF_LOG_ERROR("Failed to load DWARF file for library %s or find DWARF sections directly inside it.", m_filepath); ++ return false; ++ } ++ DWARF_LOG_INFO("No separate .debuginfo file for library %s. It already contains the required DWARF sections.", ++ m_filepath); ++ if (!create_new_dwarf_file(m_filepath)) { ++ return false; ++ } ++ } ++ ++ // Store result in filename and line pointer. ++ if (!m_dwarf_file->get_filename_and_line_number(offset_in_library, filename, filename_len, line, is_pc_after_call)) { ++ DWARF_LOG_ERROR("Failed to retrieve file and line number information for %s at offset: " PTR32_FORMAT, m_filepath, ++ offset_in_library); ++ return false; ++ } ++ return true; ++} ++ ++bool ElfFile::is_valid_dwarf_file() const { ++ Elf_Shdr shdr; ++ return read_section_header(".debug_abbrev", shdr) && read_section_header(".debug_aranges", shdr) ++ && read_section_header(".debug_info", shdr) && read_section_header(".debug_line", shdr); ++} ++ ++// (1) Load the debuginfo file from the path specified in this ELF file in the .gnu_debuglink section. ++// Adapted from Serviceability Agent. ++bool ElfFile::load_dwarf_file() { ++ if (m_dwarf_file != NULL) { ++ return true; // Already opened. ++ } ++ ++ DebugInfo debug_info; ++ if (!read_debug_info(&debug_info)) { ++ DWARF_LOG_DEBUG("Could not read debug info from .gnu_debuglink section"); ++ return false; ++ } ++ ++ DwarfFilePath dwarf_file_path(debug_info); ++ return load_dwarf_file_from_same_directory(dwarf_file_path) ++ || load_dwarf_file_from_env_var_path(dwarf_file_path) ++ || load_dwarf_file_from_debug_sub_directory(dwarf_file_path) ++ || load_dwarf_file_from_usr_lib_debug(dwarf_file_path); ++} ++ ++// Read .gnu_debuglink section which contains: ++// Filename (null terminated) + 0-3 padding bytes (to 4 byte align) + CRC (4 bytes) ++bool ElfFile::read_debug_info(DebugInfo* debug_info) const { ++ Elf_Shdr shdr; ++ if (!read_section_header(".gnu_debuglink", shdr)) { ++ DWARF_LOG_DEBUG("Failed to read the .gnu_debuglink header."); ++ return false; ++ } ++ ++ if (shdr.sh_size % 4 != 0) { ++ DWARF_LOG_ERROR(".gnu_debuglink section is not 4 byte aligned (i.e. file is corrupted)"); ++ return false; ++ } ++ ++ MarkedFileReader mfd(fd()); ++ if (!mfd.has_mark() || !mfd.set_position(m_elfHdr.e_shoff)) { ++ return false; ++ } ++ ++ uint64_t filename_max_len = shdr.sh_size - DebugInfo::CRC_LEN; ++ mfd.set_position(shdr.sh_offset); ++ if (!mfd.read(&debug_info->_dwarf_filename, filename_max_len)) { ++ return false; ++ } ++ ++ if (debug_info->_dwarf_filename[filename_max_len - 1] != '\0') { ++ // Filename not null-terminated (i.e. overflowed). ++ DWARF_LOG_ERROR("Dwarf filename is not null-terminated"); ++ return false; ++ } ++ ++ return mfd.read(&debug_info->_crc, DebugInfo::CRC_LEN); ++} ++ ++bool ElfFile::DwarfFilePath::set(const char* src) { ++ int bytes_written = jio_snprintf(_path, MAX_DWARF_PATH_LENGTH, "%s", src); ++ if (bytes_written < 0 || bytes_written >= MAX_DWARF_PATH_LENGTH) { ++ DWARF_LOG_ERROR("Dwarf file path buffer is too small"); ++ return false; ++ } ++ update_null_terminator_index(); ++ return check_valid_path(); // Sanity check ++} ++ ++bool ElfFile::DwarfFilePath::set_after_last_slash(const char* src) { ++ char* last_slash = strrchr(_path, '/'); ++ if (last_slash == NULL) { ++ // Should always find a slash. ++ return false; ++ } ++ ++ uint16_t index_after_slash = (uint16_t)(last_slash + 1 - _path); ++ return copy_to_path_index(index_after_slash, src); ++} ++ ++bool ElfFile::DwarfFilePath::append(const char* src) { ++ return copy_to_path_index(_null_terminator_index, src); ++} ++ ++bool ElfFile::DwarfFilePath::copy_to_path_index(uint16_t index_in_path, const char* src) { ++ if (index_in_path >= MAX_DWARF_PATH_LENGTH - 1) { ++ // Should not override '\0' at _path[MAX_DWARF_PATH_LENGTH - 1] ++ DWARF_LOG_ERROR("Dwarf file path buffer is too small"); ++ return false; ++ } ++ ++ uint16_t max_len = MAX_DWARF_PATH_LENGTH - index_in_path; ++ int bytes_written = jio_snprintf(_path + index_in_path, max_len, "%s", src); ++ if (bytes_written < 0 || bytes_written >= max_len) { ++ DWARF_LOG_ERROR("Dwarf file path buffer is too small"); ++ return false; ++ } ++ update_null_terminator_index(); ++ return check_valid_path(); // Sanity check ++} ++ ++// Try to load the dwarf file from the same directory as the library file. ++bool ElfFile::load_dwarf_file_from_same_directory(DwarfFilePath& dwarf_file_path) { ++ if (!dwarf_file_path.set(m_filepath) ++ || !dwarf_file_path.set_filename_after_last_slash()) { ++ return false; ++ } ++ return open_valid_debuginfo_file(dwarf_file_path); ++} ++ ++// Try to load the dwarf file from a user specified path in environmental variable _JVM_DWARF_PATH. ++bool ElfFile::load_dwarf_file_from_env_var_path(DwarfFilePath& dwarf_file_path) { ++ const char* dwarf_path_from_env = ::getenv("_JVM_DWARF_PATH"); ++ if (dwarf_path_from_env != NULL) { ++ DWARF_LOG_DEBUG("_JVM_DWARF_PATH: %s", dwarf_path_from_env); ++ return (load_dwarf_file_from_env_path_folder(dwarf_file_path, dwarf_path_from_env, "/lib/server/") ++ || load_dwarf_file_from_env_path_folder(dwarf_file_path, dwarf_path_from_env, "/lib/") ++ || load_dwarf_file_from_env_path_folder(dwarf_file_path, dwarf_path_from_env, "/bin/") ++ || load_dwarf_file_from_env_path_folder(dwarf_file_path, dwarf_path_from_env, "/")); ++ } ++ return false; ++} ++ ++bool ElfFile::load_dwarf_file_from_env_path_folder(DwarfFilePath& dwarf_file_path, const char* dwarf_path_from_env, ++ const char* folder) { ++ if (!dwarf_file_path.set(dwarf_path_from_env) ++ || !dwarf_file_path.append(folder) ++ || !dwarf_file_path.append(dwarf_file_path.filename())) { ++ DWARF_LOG_ERROR("Dwarf file path buffer is too small"); ++ return false; ++ } ++ return open_valid_debuginfo_file(dwarf_file_path); ++} ++ ++// Try to load the dwarf file from a subdirectory named .debug within the directory of the library file. ++bool ElfFile::load_dwarf_file_from_debug_sub_directory(DwarfFilePath& dwarf_file_path) { ++ if (!dwarf_file_path.set(m_filepath) ++ || !dwarf_file_path.set_after_last_slash(".debug/") ++ || !dwarf_file_path.append(dwarf_file_path.filename())) { ++ DWARF_LOG_ERROR("Dwarf file path buffer is too small"); ++ return false; ++ } ++ return open_valid_debuginfo_file(dwarf_file_path); ++} ++ ++// Try to load the dwarf file from /usr/lib/debug + the full pathname. ++bool ElfFile::load_dwarf_file_from_usr_lib_debug(DwarfFilePath& dwarf_file_path) { ++ if (!dwarf_file_path.set(USR_LIB_DEBUG_DIRECTORY) ++ || !dwarf_file_path.append(m_filepath) ++ || !dwarf_file_path.set_filename_after_last_slash()) { ++ DWARF_LOG_ERROR("Dwarf file path buffer is too small"); ++ return false; ++ } ++ return open_valid_debuginfo_file(dwarf_file_path); ++} ++ ++bool ElfFile::read_section_header(const char* name, Elf_Shdr& hdr) const { ++ if (m_shdr_string_table == NULL) { ++ assert(false, "section header string table should be loaded"); ++ return false; ++ } ++ const uint8_t buf_len = 24; ++ char buf[buf_len]; ++ size_t len = strlen(name) + 1; ++ if (len > buf_len) { ++ DWARF_LOG_ERROR("Section header name buffer is too small: Required: %zu, Found: %d", len, buf_len); ++ return false; ++ } ++ ++ MarkedFileReader mfd(fd()); ++ if (!mfd.has_mark() || !mfd.set_position(m_elfHdr.e_shoff)) { ++ return false; ++ } ++ ++ for (int index = 0; index < m_elfHdr.e_shnum; index++) { ++ if (!mfd.read((void*)&hdr, sizeof(hdr))) { ++ return false; ++ } ++ if (m_shdr_string_table->string_at(hdr.sh_name, buf, buf_len)) { ++ if (strncmp(buf, name, buf_len) == 0) { ++ return true; ++ } ++ } ++ } ++ return false; ++} ++ ++// Taken from https://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files ++static const uint32_t crc32_table[256] = { ++ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, ++ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, ++ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, ++ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, ++ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, ++ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, ++ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, ++ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, ++ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, ++ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a, ++ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, ++ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, ++ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, ++ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, ++ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, ++ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, ++ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, ++ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, ++ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, ++ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, ++ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, ++ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, ++ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010, ++ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, ++ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, ++ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, ++ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, ++ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, ++ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, ++ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, ++ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, ++ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, ++ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, ++ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c, ++ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, ++ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, ++ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, ++ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, ++ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, ++ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, ++ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, ++ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242, ++ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, ++ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, ++ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278, ++ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, ++ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, ++ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, ++ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, ++ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, ++ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, ++ 0x2d02ef8d ++ }; ++ ++bool ElfFile::open_valid_debuginfo_file(const DwarfFilePath& dwarf_file_path) { ++ if (m_dwarf_file != NULL) { ++ // Already opened. ++ return true; ++ } ++ ++ const char* filepath = dwarf_file_path.path(); ++ FILE* file = fopen(filepath, "r"); ++ if (file == NULL) { ++ DWARF_LOG_DEBUG("Could not open dwarf file %s ", filepath); ++ return false; ++ } ++ ++ uint32_t file_crc = get_file_crc(file); ++ fclose(file); // Close it here to reopen it again when the DwarfFile object is created below. ++ ++ if (dwarf_file_path.crc() != file_crc) { ++ // Must be equal, otherwise the file is corrupted. ++ DWARF_LOG_ERROR("CRC did not match. Expected: " PTR32_FORMAT ", found: " PTR32_FORMAT, dwarf_file_path.crc(), ++ file_crc); ++ return false; ++ } ++ return create_new_dwarf_file(filepath); ++} ++ ++uint32_t ElfFile::get_file_crc(FILE* const file) { ++ uint32_t file_crc = 0; ++ uint8_t buffer[8 * 1024]; ++ MarkedFileReader reader(file); ++ while (true) { ++ size_t len = reader.read_buffer(buffer, sizeof(buffer)); ++ if (len == 0) { ++ break; ++ } ++ file_crc = gnu_debuglink_crc32(file_crc, buffer, len); ++ } ++ return file_crc; ++} ++ ++// The CRC used in gnu_debuglink, retrieved from ++// http://sourceware.org/gdb/current/onlinedocs/gdb/Separate-Debug-Files.html#Separate-Debug-Files. ++uint32_t ElfFile::gnu_debuglink_crc32(uint32_t crc, uint8_t* buf, const size_t len) { ++ crc = ~crc; ++ for (uint8_t* end = buf + len; buf < end; buf++) { ++ crc = crc32_table[(crc ^ *buf) & 0xffu] ^ (crc >> 8u); ++ } ++ return ~crc; ++} ++ ++bool ElfFile::create_new_dwarf_file(const char* filepath) { ++ DWARF_LOG_SUMMARY("Open DWARF file: %s", filepath); ++ m_dwarf_file = new (std::nothrow) DwarfFile(filepath); ++ if (m_dwarf_file == NULL) { ++ DWARF_LOG_ERROR("Failed to create new DwarfFile object for %s.", m_filepath); ++ return false; ++ } ++ if (!m_dwarf_file->is_valid_dwarf_file()) { ++ DWARF_LOG_ERROR("Did not find required DWARF sections in %s", filepath); ++ return false; ++ } ++ return true; ++} ++ ++// Starting point of reading line number and filename information from the DWARF file. ++bool DwarfFile::get_filename_and_line_number(const uint32_t offset_in_library, char* filename, const size_t filename_len, ++ int* line, const bool is_pc_after_call) { ++ DebugAranges debug_aranges(this); ++ uint32_t compilation_unit_offset = 0; // 4-bytes for 32-bit DWARF ++ if (!debug_aranges.find_compilation_unit_offset(offset_in_library, &compilation_unit_offset)) { ++ DWARF_LOG_ERROR("Failed to find .debug_info offset for the compilation unit."); ++ return false; ++ } ++ DWARF_LOG_INFO(".debug_info offset: " PTR32_FORMAT, compilation_unit_offset); ++ ++ CompilationUnit compilation_unit(this, compilation_unit_offset); ++ uint32_t debug_line_offset = 0; // 4-bytes for 32-bit DWARF ++ if (!compilation_unit.find_debug_line_offset(&debug_line_offset)) { ++ DWARF_LOG_ERROR("Failed to find .debug_line offset for the line number program."); ++ return false; ++ } ++ DWARF_LOG_INFO(".debug_line offset: " PTR32_FORMAT, debug_line_offset); ++ ++ LineNumberProgram line_number_program(this, offset_in_library, debug_line_offset, is_pc_after_call); ++ if (!line_number_program.find_filename_and_line_number(filename, filename_len, line)) { ++ DWARF_LOG_ERROR("Failed to process the line number program correctly."); ++ return false; ++ } ++ return true; ++} ++ ++// (2) The .debug_aranges section contains a number of entries/sets. Each set contains one or multiple address range descriptors of the ++// form [beginning_address, beginning_address+length). Start reading these sets and their descriptors until we find one that contains ++// 'offset_in_library'. Read the debug_info_offset field from the header of this set which defines the offset for the compilation unit. ++// This process is described in section 6.1.2 of the DWARF 4 spec. ++bool DwarfFile::DebugAranges::find_compilation_unit_offset(const uint32_t offset_in_library, uint32_t* compilation_unit_offset) { ++ if (!read_section_header()) { ++ DWARF_LOG_ERROR("Failed to read a .debug_aranges header."); ++ return false; ++ } ++ ++ DebugArangesSetHeader set_header; ++ bool found_matching_set = false; ++ while (_reader.has_bytes_left()) { ++ // Read multiple sets and therefore multiple headers. ++ if (!read_set_header(set_header)) { ++ DWARF_LOG_ERROR("Failed to read a .debug_aranges header."); ++ return false; ++ } ++ ++ if (!read_address_descriptors(offset_in_library, found_matching_set)) { ++ return false; ++ } ++ ++ if (found_matching_set) { ++ // Found the correct set, read the debug_info_offset from the header of this set. ++ DWARF_LOG_INFO(".debug_aranges offset: " PTR32_FORMAT, (uint32_t)_reader.get_position()); ++ *compilation_unit_offset = set_header._debug_info_offset; ++ return true; ++ } ++ } ++ ++ assert(false, "No address descriptor found containing offset_in_library."); ++ return false; ++} ++ ++bool DwarfFile::DebugAranges::read_section_header() { ++ Elf_Shdr shdr; ++ if (!_dwarf_file->read_section_header(".debug_aranges", shdr)) { ++ return false; ++ } ++ ++ _section_start_address = shdr.sh_offset; ++ _reader.set_max_pos(shdr.sh_offset + shdr.sh_size); ++ return _reader.set_position(shdr.sh_offset); ++} ++ ++// Parse set header as specified in section 6.1.2 of the DWARF 4 spec. ++bool DwarfFile::DebugAranges::read_set_header(DebugArangesSetHeader& header) { ++ if (!_reader.read_dword(&header._unit_length) || header._unit_length == 0xFFFFFFFF) { ++ // For 64-bit DWARF, the first 32-bit value is 0xFFFFFFFF. The current implementation only supports 32-bit DWARF ++ // format since GCC only emits 32-bit DWARF. ++ DWARF_LOG_ERROR("64-bit DWARF is not supported for .debug_aranges") ++ return false; ++ } ++ ++ if (!_reader.read_word(&header._version) || header._version != 2) { ++ // DWARF 4 uses version 2 as specified in Appendix F of the DWARF 4 spec. ++ DWARF_LOG_ERROR(".debug_aranges in unsupported DWARF version %" PRIu16, header._version) ++ return false; ++ } ++ ++ if (!_reader.read_dword(&header._debug_info_offset)) { ++ return false; ++ } ++ ++ if (!_reader.read_byte(&header._address_size) || header._address_size != DwarfFile::ADDRESS_SIZE) { ++ // Addresses must be either 4 bytes for 32-bit architectures or 8 bytes for 64-bit architectures. ++ DWARF_LOG_ERROR(".debug_aranges specifies wrong address size %" PRIu8, header._address_size); ++ return false; ++ } ++ ++ if (!_reader.read_byte(&header._segment_size) || header._segment_size != 0) { ++ // Segment size should be 0. ++ DWARF_LOG_ERROR(".debug_aranges segment size is non-zero: %" PRIu8, header._segment_size); ++ return false; ++ } ++ ++ // We must align to twice the address size. ++ uint8_t alignment = DwarfFile::ADDRESS_SIZE * 2; ++ uint8_t padding = alignment - (_reader.get_position() - _section_start_address) % alignment; ++ return _reader.move_position(padding); ++} ++ ++bool DwarfFile::DebugAranges::read_address_descriptors(const uint32_t offset_in_library, bool& found_matching_set) { ++ AddressDescriptor descriptor; ++ do { ++ if (!read_address_descriptor(descriptor)) { ++ return false; ++ } ++ ++ if (does_match_offset(offset_in_library, descriptor)) { ++ found_matching_set = true; ++ return true; ++ } ++ } while (!is_terminating_entry(descriptor) && _reader.has_bytes_left()); ++ ++ // Set does not match offset_in_library. Continue with next. ++ return true; ++} ++ ++bool DwarfFile::DebugAranges::read_address_descriptor(AddressDescriptor& descriptor) { ++ return _reader.read_address_sized(&descriptor.beginning_address) ++ && _reader.read_address_sized(&descriptor.range_length); ++} ++ ++bool DwarfFile::DebugAranges::does_match_offset(const uint32_t offset_in_library, const AddressDescriptor& descriptor) { ++ return descriptor.beginning_address <= offset_in_library ++ && offset_in_library < descriptor.beginning_address + descriptor.range_length; ++} ++ ++bool DwarfFile::DebugAranges::is_terminating_entry(const AddressDescriptor& descriptor) { ++ return descriptor.beginning_address == 0 && descriptor.range_length == 0; ++} ++ ++// Find the .debug_line offset for the line number program by reading from the .debug_abbrev and .debug_info section. ++bool DwarfFile::CompilationUnit::find_debug_line_offset(uint32_t* debug_line_offset) { ++ // (3a,b) ++ if (!read_header()) { ++ DWARF_LOG_ERROR("Failed to read the compilation unit header."); ++ return false; ++ } ++ ++ // (3c) Read the abbreviation code immediately following the compilation unit header which is an offset to the ++ // correct abbreviation table in .debug_abbrev for this compilation unit. ++ uint64_t abbrev_code; ++ if (!_reader.read_uleb128(&abbrev_code)) { ++ return false; ++ } ++ ++ DebugAbbrev debug_abbrev(_dwarf_file, this); ++ if (!debug_abbrev.read_section_header(_header._debug_abbrev_offset)) { ++ DWARF_LOG_ERROR("Failed to read the .debug_abbrev header at " PTR32_FORMAT, _header._debug_abbrev_offset); ++ return false; ++ } ++ if (!debug_abbrev.find_debug_line_offset(abbrev_code)) { ++ return false; ++ } ++ *debug_line_offset = _debug_line_offset; // Result was stored in _debug_line_offset. ++ return true; ++} ++ ++// (3a) Parse header as specified in section 7.5.1.1 of the DWARF 4 spec. ++bool DwarfFile::CompilationUnit::read_header() { ++ Elf_Shdr shdr; ++ if (!_dwarf_file->read_section_header(".debug_info", shdr)) { ++ DWARF_LOG_ERROR("Failed to read the .debug_info section header."); ++ return false; ++ } ++ ++ if (!_reader.set_position(shdr.sh_offset + _compilation_unit_offset)) { ++ return false; ++ } ++ ++ if (!_reader.read_dword(&_header._unit_length) || _header._unit_length == 0xFFFFFFFF) { ++ // For 64-bit DWARF, the first 32-bit value is 0xFFFFFFFF. The current implementation only supports 32-bit DWARF ++ // format since GCC only emits 32-bit DWARF. ++ DWARF_LOG_ERROR("64-bit DWARF is not supported for .debug_info") ++ return false; ++ } ++ ++ if (!_reader.read_word(&_header._version) || _header._version != 4) { ++ // DWARF 4 uses version 4 as specified in Appendix F of the DWARF 4 spec. ++ DWARF_LOG_ERROR(".debug_info in unsupported DWARF version %" PRIu16, _header._version) ++ return false; ++ } ++ ++ // (3b) Offset into .debug_abbrev section. ++ if (!_reader.read_dword(&_header._debug_abbrev_offset)) { ++ return false; ++ } ++ ++ if (!_reader.read_byte(&_header._address_size) || _header._address_size != DwarfFile::ADDRESS_SIZE) { ++ // Addresses must be either 4 bytes for 32-bit architectures or 8 bytes for 64-bit architectures. ++ DWARF_LOG_ERROR(".debug_info specifies wrong address size %" PRIu8, _header._address_size); ++ return false; ++ } ++ ++ // Add because _unit_length is not included. ++ _reader.set_max_pos(_reader.get_position() + _header._unit_length + 4); ++ return true; ++} ++ ++bool DwarfFile::DebugAbbrev::read_section_header(uint32_t debug_abbrev_offset) { ++ Elf_Shdr shdr; ++ if (!_dwarf_file->read_section_header(".debug_abbrev", shdr)) { ++ return false; ++ } ++ ++ _reader.set_max_pos(shdr.sh_offset + shdr.sh_size); ++ if (!_reader.set_position(shdr.sh_offset + debug_abbrev_offset)) { ++ return false; ++ } ++ return true; ++} ++ ++// (3d) The abbreviations table for a compilation unit consists of a series of abbreviation declarations. Each declaration ++// specifies an abbrev code and a tag. Parse all declarations until we find the declaration which matches 'abbrev_code'. ++// Read the attribute values from the compilation unit in .debug_info by using the format described in the declaration. ++// This process is described in section 7.5 and 7.5.3 of the DWARF 4 spec. ++bool DwarfFile::DebugAbbrev::find_debug_line_offset(const uint64_t abbrev_code) { ++ DWARF_LOG_TRACE("Series of declarations [code, tag]:"); ++ AbbreviationDeclaration declaration; ++ while (_reader.has_bytes_left()) { ++ if (!read_declaration(declaration)) { ++ return false; ++ } ++ ++ DWARF_LOG_TRACE(" Series of attributes [name, form]:"); ++ if (declaration._abbrev_code == abbrev_code) { ++ // Found the correct declaration. ++ if (is_wrong_or_unsupported_format(declaration)) { ++ return false; ++ } ++ DWARF_LOG_INFO(".debug_abbrev offset: " PTR32_FORMAT, (uint32_t)_reader.get_position()); ++ DWARF_LOG_TRACE(" Read the following attribute values from compilation unit:"); ++ return read_attribute_specifications(true); ++ } else { ++ // Not the correct declaration. Read its attributes and continue with the next declaration. ++ if (!read_attribute_specifications(false)) { ++ return false; ++ } ++ } ++ } ++ ++ assert(false, ".debug_line offset not found"); ++ return false; ++} ++ ++bool DwarfFile::DebugAbbrev::read_declaration(DwarfFile::DebugAbbrev::AbbreviationDeclaration& declaration) { ++ if (!_reader.read_uleb128(&declaration._abbrev_code)) { ++ return false; ++ } ++ ++ if (declaration._abbrev_code == 0) { ++ // Reached the end of the abbreviation declarations for this compilation unit. ++ DWARF_LOG_ERROR("abbrev_code not found in any declaration"); ++ return false; ++ } ++ ++ if (!_reader.read_uleb128(&declaration._tag) || !_reader.read_byte(&declaration._has_children)) { ++ return false; ++ } ++ ++ DWARF_LOG_TRACE("Code: 0x" UINT64_FORMAT_X ", Tag: 0x" UINT64_FORMAT_X, declaration._abbrev_code, declaration._tag); ++ return true; ++} ++ ++bool DwarfFile::DebugAbbrev::is_wrong_or_unsupported_format(const DwarfFile::DebugAbbrev::AbbreviationDeclaration& declaration) { ++ if (declaration._tag != DW_TAG_compile_unit) { ++ // Is not DW_TAG_compile_unit as specified in Figure 18 in section 7.5 of the DWARF 4 spec. It could also ++ // be DW_TAG_partial_unit (0x3c) which is currently not supported by this parser. ++ DWARF_LOG_ERROR("Found unsupported tag in compilation unit: " UINT64_FORMAT_X, declaration._tag); ++ return true; ++ } ++ if (declaration._has_children != DW_CHILDREN_yes) { ++ DWARF_LOG_ERROR("Must have children but none specified"); ++ return true; ++ } ++ return false; ++} ++ ++// Read the attribute names and forms which define the actual attribute values that follow the abbrev code in the compilation unit. All ++// attributes need to be read from the compilation unit until we reach the DW_AT_stmt_list attribute which specifies the offset for the ++// line number program into the .debug_line section. The offset is stored in the _debug_line_offset field of the compilation unit. ++bool DwarfFile::DebugAbbrev::read_attribute_specifications(const bool is_DW_TAG_compile_unit) { ++ AttributeSpecification attribute_specification; ++ while (_reader.has_bytes_left()) { ++ if (!read_attribute_specification(attribute_specification)) { ++ return false; ++ } ++ ++ if (is_terminating_specification(attribute_specification)) { ++ // Parsed all attributes of this declaration. ++ if (is_DW_TAG_compile_unit) { ++ DWARF_LOG_ERROR("Did not find DW_AT_stmt_list in .debug_abbrev"); ++ return false; ++ } else { ++ // Continue with next declaration if this was not DW_TAG_compile_unit. ++ return true; ++ } ++ } ++ ++ if (is_DW_TAG_compile_unit) { ++ // Read attribute from compilation unit ++ if (attribute_specification._name == DW_AT_stmt_list) { ++ // This attribute represents the .debug_line offset. Read it and then stop parsing. ++ return _compilation_unit->read_attribute_value(attribute_specification._form, true); ++ } else { ++ // Not DW_AT_stmt_list, read it and continue with the next attribute. ++ if (!_compilation_unit->read_attribute_value(attribute_specification._form, false)) { ++ return false; ++ } ++ } ++ } ++ } ++ ++ assert(false, ".debug_abbrev section appears to be corrupted"); ++ return false; ++} ++ ++bool DwarfFile::DebugAbbrev::read_attribute_specification(DwarfFile::DebugAbbrev::AttributeSpecification& specification) { ++ bool result = _reader.read_uleb128(&specification._name) && _reader.read_uleb128(&specification._form); ++ DWARF_LOG_TRACE(" Name: 0x" UINT64_FORMAT_X ", Form: 0x" UINT64_FORMAT_X, ++ specification._name, specification._form); ++ return result; ++} ++ ++bool DwarfFile::DebugAbbrev::is_terminating_specification(const DwarfFile::DebugAbbrev::AttributeSpecification& specification) { ++ return specification._name == 0 && specification._form == 0; ++} ++ ++ ++// (3e) Read the actual attribute values from the compilation unit in the .debug_info section. Each attribute has an encoding ++// that specifies which values need to be read for it. This is specified in section 7.5.4 of the DWARF 4 spec. ++// If is_DW_AT_stmt_list_attribute is: ++// - False: Ignore the read attribute value. ++// - True: We are going to read the attribute value of the DW_AT_stmt_list attribute which specifies the offset into the ++// .debug_line section for the line number program. Store this offset in the _debug_line_offset field. ++bool DwarfFile::CompilationUnit::read_attribute_value(const uint64_t attribute_form, const bool is_DW_AT_stmt_list_attribute) { ++ // Reset to the stored _cur_pos of the reader since the DebugAbbrev reader changed the index into the file with its reader. ++ _reader.update_to_stored_position(); ++ uint8_t next_byte = 0; ++ uint16_t next_word = 0; ++ uint32_t next_dword = 0; ++ uint64_t next_qword = 0; ++ ++ switch (attribute_form) { ++ case DW_FORM_addr: ++ // Move position by the size of an address. ++ _reader.move_position(DwarfFile::ADDRESS_SIZE); ++ break; ++ case DW_FORM_block2: ++ // New position: length + data length (next_word) ++ if (!_reader.read_word(&next_word) || !_reader.move_position(next_word)) { ++ return false; ++ } ++ break; ++ case DW_FORM_block4: ++ // New position: length + data length (next_dword) ++ if (!_reader.read_dword(&next_dword) || !_reader.move_position(next_dword)) { ++ return false; ++ } ++ break; ++ case DW_FORM_data2: ++ case DW_FORM_ref2: ++ if (!_reader.move_position(2)) { ++ return false; ++ } ++ break; ++ case DW_FORM_data4: ++ case DW_FORM_strp: // 4 bytes in 32-bit DWARF ++ case DW_FORM_ref_addr: // second type of reference: 4 bytes in 32-bit DWARF ++ case DW_FORM_ref4: ++ if (!_reader.move_position(4)) { ++ return false; ++ } ++ break; ++ case DW_FORM_data8: ++ case DW_FORM_ref8: ++ case DW_FORM_ref_sig8: // 64-bit type signature ++ if (!_reader.move_position(8)) { ++ return false; ++ } ++ break; ++ case DW_FORM_string: ++ if (!_reader.read_string()) { ++ return false; ++ } ++ break; ++ case DW_FORM_block: ++ case DW_FORM_exprloc: ++ // New position: length + data length (next_qword). ++ if (!_reader.read_uleb128(&next_qword) || !_reader.move_position(next_qword)) { ++ return false; ++ } ++ break; ++ case DW_FORM_block1: ++ // New position: length + data length (next_byte). ++ if (!_reader.read_byte(&next_byte) || !_reader.move_position(next_byte)) { ++ return false; ++ } ++ break; ++ case DW_FORM_data1: ++ case DW_FORM_ref1: ++ case DW_FORM_flag: ++ case DW_FORM_flag_present: ++ if (!_reader.move_position(1)) { ++ return false; ++ } ++ break; ++ case DW_FORM_sdata: ++ case DW_FORM_udata: ++ case DW_FORM_ref_udata: ++ if (!_reader.read_uleb128(&next_qword)) { ++ return false; ++ } ++ break; ++ case DW_FORM_indirect: ++ // Should not be used and therefore is not supported by this parser. ++ DWARF_LOG_ERROR("DW_FORM_indirect is not supported."); ++ return false; ++ case DW_FORM_sec_offset: ++ if (is_DW_AT_stmt_list_attribute) { ++ // DW_AT_stmt_list has the DW_FORM_sec_offset attribute encoding. Store the result in _debug_line_offset. ++ // 4 bytes for 32-bit DWARF. ++ DWARF_LOG_TRACE(" Name: DW_AT_stmt_list, Form: DW_FORM_sec_offset"); ++ DWARF_LOG_TRACE(" Reading .debug_line offset from compilation unit at " PTR32_FORMAT, ++ (uint32_t)_reader.get_position()); ++ if (!_reader.read_dword(&_debug_line_offset)) { ++ return false; ++ } ++ break; ++ } else { ++ if (!_reader.move_position(DwarfFile::DWARF_SECTION_OFFSET_SIZE)) { ++ return false; ++ } ++ break; ++ } ++ default: ++ assert(false, "Unknown DW_FORM_* attribute encoding."); ++ return false; ++ } ++ // Reset the index into the file to the original position where the DebugAbbrev reader stopped reading before calling this method. ++ _reader.reset_to_previous_position(); ++ return true; ++} ++ ++bool DwarfFile::LineNumberProgram::find_filename_and_line_number(char* filename, const size_t filename_len, int* line) { ++ if (!read_header()) { ++ DWARF_LOG_ERROR("Failed to parse the line number program header correctly."); ++ return false; ++ } ++ return run_line_number_program(filename, filename_len, line); ++} ++ ++// Parsing header as specified in section 6.2.4 of DWARF 4 spec. We do not read the file_names field, yet. ++bool DwarfFile::LineNumberProgram::read_header() { ++ Elf_Shdr shdr; ++ if (!_dwarf_file->read_section_header(".debug_line", shdr)) { ++ DWARF_LOG_ERROR("Failed to read the .debug_line section header."); ++ return false; ++ } ++ ++ if (!_reader.set_position(shdr.sh_offset + _debug_line_offset)) { ++ return false; ++ } ++ ++ if (!_reader.read_dword(&_header._unit_length) || _header._unit_length == 0xFFFFFFFF) { ++ // For 64-bit DWARF, the first 32-bit value is 0xFFFFFFFF. The current implementation only supports 32-bit DWARF ++ // format since GCC only emits 32-bit DWARF. ++ DWARF_LOG_ERROR("64-bit DWARF is not supported for .debug_line") ++ return false; ++ } ++ ++ if (!_reader.read_word(&_header._version) || _header._version < 2 || _header._version > 4) { ++ // DWARF 3 uses version 3 and DWARF 4 uses version 4 as specified in Appendix F of the DWARF 3 and 4 spec, respectively. ++ // For some reason, GCC is not following the standard here. While GCC emits DWARF 4 for the other parsed sections, ++ // it chooses a different DWARF standard for .debug_line based on the GCC version: ++ // - GCC 8 and earlier: .debug_line is in DWARF 2 format (= version 2). ++ // - GCC 9 and 10: .debug_line is in DWARF 3 format (= version 3). ++ // - GCC 11: .debug_line is in DWARF 4 format (= version 4). ++ DWARF_LOG_ERROR(".debug_line in unsupported DWARF version %" PRIu16, _header._version) ++ return false; ++ } ++ ++ if (!_reader.read_dword(&_header._header_length)) { ++ return false; ++ } ++ ++ // To ensure not to read too many bytes in case of file corruption when reading the path_names field. ++ _reader.set_max_pos(_reader.get_position() + _header._header_length); ++ ++ if (!_reader.read_byte(&_header._minimum_instruction_length)) { ++ return false; ++ } ++ ++ if (_header._version == 4) { ++ if (!_reader.read_byte(&_header._maximum_operations_per_instruction)) { ++ return false; ++ } ++ } ++ ++ if (!_reader.read_byte(&_header._default_is_stmt)) { ++ return false; ++ } ++ ++ if (!_reader.read_sbyte(&_header._line_base)) { ++ return false; ++ } ++ ++ if (!_reader.read_byte(&_header._line_range)) { ++ return false; ++ } ++ ++ if (!_reader.read_byte(&_header._opcode_base) || _header._opcode_base - 1 != 12) { ++ // There are 12 standard opcodes for DWARF 3 and 4. ++ DWARF_LOG_ERROR("Wrong number of opcodes: %" PRIu8, _header._opcode_base) ++ return false; ++ } ++ ++ for (uint8_t i = 0; i < _header._opcode_base - 1; i++) { ++ if (!_reader.read_byte(&_header._standard_opcode_lengths[i])) { ++ return false; ++ } ++ } ++ ++ // Read field include_directories which is a sequence of path names. These are terminated by a single null byte. ++ // We do not care about them, just read the strings and move on. ++ while (_reader.read_string()) { } ++ ++ // Delay reading file_names until we found the correct file index in the line number program. Store the position where ++ // the file names start to parse them later. We directly jump to the line number program which starts at offset ++ // header_size (=HEADER_DESCRIPTION_BYTES + _header_length) + _debug_line_offset ++ _header._file_names_offset = _reader.get_position(); ++ uint32_t header_size = LineNumberProgramHeader::HEADER_DESCRIPTION_BYTES + _header._header_length; ++ if (!_reader.set_position(shdr.sh_offset + header_size + _debug_line_offset)) { ++ return false; ++ } ++ ++ // Now reset the max position to where the line number information for this compilation unit ends (i.e. where the state ++ // machine gets terminated). Add 4 bytes to the offset because the size of the _unit_length field is not included in this ++ // value. ++ _reader.set_max_pos(shdr.sh_offset + _debug_line_offset + _header._unit_length + 4); ++ return true; ++} ++ ++// Create the line number information matrix as described in section 6.2 of the DWARF 4 spec. Try to find the correct entry ++// by comparing the address register belonging to each matrix row with _offset_in_library. Once it is found, we can read ++// the line number from the line register and the filename by parsing the file_names list from the header until we reach ++// the correct filename as specified by the file register. ++// ++// If space was not a problem, the .debug_line section could provide a large matrix that contains an entry for each ++// compiler instruction that contains the line number, the column number, the filename etc. But that's impractical. ++// Two techniques optimize such a matrix: ++// (1) If two offsets share the same file, line and column (and discriminator) information, the row is dropped. ++// (2) We store a stream of bytes that represent opcodes to be executed in a well-defined state machine language ++// instead of actually storing the entire matrix row by row. ++// ++// Let's consider a simple example: ++// 25: int iFld = 42; ++// 26: ++// 27: void bar(int i) { ++// 28: } ++// 29: ++// 30: void foo() { ++// 31: bar(*iFld); ++// 32: } ++// ++// Disassembly of foo() with source code: ++// 30: void foo() { ++// 0x55d132: 55 push rbp ++// 0x55d133: 48 89 e5 mov rbp,rsp ++// 31: bar(*iFld); ++// 0x55d136: 48 8b 05 b3 ee e8 01 mov rax,QWORD PTR [rip+0x1e8eeb3] # 23ebff0 ++// 0x55d13d: 8b 00 mov eax,DWORD PTR [rax] ++// 0x55d13f: 89 c7 mov edi,eax ++// 0x55d141: e8 e2 ff ff ff call 55d128 <_Z3bari> ++// 32: } ++// 0x55d146: 90 nop ++// 0x55d147: 5d pop rbp ++// 0x55d148: c3 ret ++// ++// This would produce the following matrix for foo() where duplicated lines (0x55d133, 0x55d13d, 0x55d13f) were removed ++// according to (1): ++// Address: Line: Column: File: ++// 0x55d132 30 12 1 ++// 0x55d136 31 6 1 ++// 0x55d146 32 1 1 ++// ++// When trying to get the line number for a PC, which is translated into an offset address x into the library file, we can either: ++// - Directly find the last entry in the matrix for which address == x (there could be multiple entries with the same address). ++// - If there is no matching address for x: ++// 1. Find two consecutive entries in the matrix for which: address_entry_1 < x < address_entry_2. ++// 2. Then take the entry of address_entry_1. ++// E.g. x = 0x55d13f -> 0x55d136 < 0x55d13f < 0x55d146 -> Take entry 0x55d136. ++// ++// Enable logging with debug level to print the generated line number information matrix. ++bool DwarfFile::LineNumberProgram::run_line_number_program(char* filename, const size_t filename_len, int* line) { ++ DWARF_LOG_DEBUG(" "); ++ DWARF_LOG_DEBUG("Line Number Information Matrix"); ++ DWARF_LOG_DEBUG("------------------------------"); ++#ifndef _LP64 ++ DWARF_LOG_DEBUG("Address: Line: Column: File:"); ++#else ++ DWARF_LOG_DEBUG("Address: Line: Column: File:"); ++#endif ++ _state = new (std::nothrow) LineNumberProgramState(_header); ++ if (_state == NULL) { ++ DWARF_LOG_ERROR("Failed to create new LineNumberProgramState object"); ++ return false; ++ } ++ uintptr_t previous_address = 0; ++ uint32_t previous_file = 0; ++ uint32_t previous_line = 0; ++ while (_reader.has_bytes_left()) { ++ if (!apply_opcode()) { ++ assert(false, "Could not apply opcode"); ++ return false; ++ } ++ ++ if (_state->_append_row) { ++ // Append a new line to the line number information matrix. ++ if (_state->_first_entry_in_sequence) { ++ // First entry in sequence: Check if _offset_in_library >= _state->address. If not, then all following entries ++ // belonging to this sequence cannot match our _offset_in_library because the addresses are always increasing ++ // in a sequence. ++ _state->_can_sequence_match_offset = _offset_in_library >= _state->_address; ++ _state->_first_entry_in_sequence = false; ++ } ++ if (does_offset_match_entry(previous_address, previous_file, previous_line)) { ++ // We are using an int for the line number which should never be larger than INT_MAX for any files. ++ *line = (int)_state->_line; ++ return get_filename_from_header(_state->_file, filename, filename_len); ++ } ++ ++ // We do not actually store the matrix while searching the correct entry. Enable logging to print/debug it. ++ DWARF_LOG_DEBUG(INTPTR_FORMAT " %-5u %-3u %-4u", ++ _state->_address, _state->_line, _state->_column, _state->_file); ++ previous_file = _state->_file; ++ previous_line = _state->_line; ++ previous_address = _state->_address; ++ _state->_append_row = false; ++ if (_state->_do_reset) { ++ // Current sequence terminated. ++ _state->reset_fields(); ++ } ++ } ++ } ++ ++ return false; ++} ++ ++// Apply next opcode to update the state machine. ++bool DwarfFile::LineNumberProgram::apply_opcode() { ++ uint8_t opcode; ++ if (!_reader.read_byte(&opcode)) { ++ return false; ++ } ++ ++ DWARF_LOG_TRACE(" Opcode: 0x%02x ", opcode); ++ if (opcode == 0) { ++ // Extended opcodes start with a zero byte. ++ if (!apply_extended_opcode()) { ++ assert(false, "Could not apply extended opcode"); ++ return false; ++ } ++ } else if (opcode <= 12) { ++ // 12 standard opcodes in DWARF 3 and 4. ++ if (!apply_standard_opcode(opcode)) { ++ assert(false, "Could not apply standard opcode"); ++ return false; ++ } ++ } else { ++ // Special opcodes range from 13 until 255. ++ apply_special_opcode(opcode); ++ } ++ return true; ++} ++ ++// Specified in section 6.2.5.3 of the DWARF 4 spec. ++bool DwarfFile::LineNumberProgram::apply_extended_opcode() { ++ uint64_t extended_opcode_length; // Does not include the already written zero byte and the length leb128. ++ uint8_t extended_opcode; ++ if (!_reader.read_uleb128(&extended_opcode_length) || !_reader.read_byte(&extended_opcode)) { ++ return false; ++ } ++ ++ switch (extended_opcode) { ++ case DW_LNE_end_sequence: // No operands ++ DWARF_LOG_TRACE(" DW_LNE_end_sequence"); ++ _state->_end_sequence = true; ++ _state->_append_row = true; ++ _state->_do_reset = true; ++ break; ++ case DW_LNE_set_address: // 1 operand ++ if (!_reader.read_address_sized(&_state->_address)) { ++ return false; ++ } ++ DWARF_LOG_TRACE(" DW_LNE_set_address " INTPTR_FORMAT, _state->_address); ++ if (_state->_dwarf_version == 4) { ++ _state->_op_index = 0; ++ } ++ break; ++ case DW_LNE_define_file: // 4 operands ++ DWARF_LOG_TRACE(" DW_LNE_define_file"); ++ if (!_reader.read_string()) { ++ return false; ++ } ++ // Operand 2-4: uleb128 numbers we do not care about. ++ if (!_reader.read_uleb128_ignore() ++ || !_reader.read_uleb128_ignore() ++ || !_reader.read_uleb128_ignore()) { ++ return false; ++ } ++ break; ++ case DW_LNE_set_discriminator: // 1 operand ++ DWARF_LOG_TRACE(" DW_LNE_set_discriminator"); ++ uint64_t discriminator; ++ // For some reason, GCC emits this opcode even for earlier versions than DWARF 4 which introduced this opcode. ++ // We need to consume it. ++ if (!_reader.read_uleb128(&discriminator, 4)) { ++ // Must be an unsigned integer as specified in section 6.2.2 of the DWARF 4 spec for the discriminator register. ++ return false; ++ } ++ _state->_discriminator = discriminator; ++ break; ++ default: ++ assert(false, "Unknown extended opcode"); ++ return false; ++ } ++ return true; ++} ++ ++// Specified in section 6.2.5.2 of the DWARF 4 spec. ++bool DwarfFile::LineNumberProgram::apply_standard_opcode(const uint8_t opcode) { ++ switch (opcode) { ++ case DW_LNS_copy: // No operands ++ DWARF_LOG_TRACE(" DW_LNS_copy"); ++ _state->_append_row = true; ++ _state->_basic_block = false; ++ _state->_prologue_end = false; ++ _state->_epilogue_begin = false; ++ if (_state->_dwarf_version == 4) { ++ _state->_discriminator = 0; ++ } ++ break; ++ case DW_LNS_advance_pc: { // 1 operand ++ uint64_t operation_advance; ++ if (!_reader.read_uleb128(&operation_advance, 4)) { ++ // Must be at most 4 bytes because the index register is only 4 bytes wide. ++ return false; ++ } ++ _state->add_to_address_register(operation_advance, _header); ++ if (_state->_dwarf_version == 4) { ++ _state->set_index_register(operation_advance, _header); ++ } ++ DWARF_LOG_TRACE(" DW_LNS_advance_pc (" INTPTR_FORMAT ")", _state->_address); ++ break; ++ } ++ case DW_LNS_advance_line: // 1 operand ++ int64_t line; ++ if (!_reader.read_sleb128(&line, 4)) { ++ // line register is 4 bytes wide. ++ return false; ++ } ++ _state->_line += line; ++ DWARF_LOG_TRACE(" DW_LNS_advance_line (%d)", _state->_line); ++ break; ++ case DW_LNS_set_file: // 1 operand ++ uint64_t file; ++ if (!_reader.read_uleb128(&file, 4)) { ++ // file register is 4 bytes wide. ++ return false; ++ } ++ _state->_file = file; ++ DWARF_LOG_TRACE(" DW_LNS_set_file (%u)", _state->_file); ++ break; ++ case DW_LNS_set_column: // 1 operand ++ uint64_t column; ++ if (!_reader.read_uleb128(&column, 4)) { ++ // column register is 4 bytes wide. ++ return false; ++ } ++ _state->_column = column; ++ DWARF_LOG_TRACE(" DW_LNS_set_column (%u)", _state->_column); ++ break; ++ case DW_LNS_negate_stmt: // No operands ++ DWARF_LOG_TRACE(" DW_LNS_negate_stmt"); ++ _state->_is_stmt = !_state->_is_stmt; ++ break; ++ case DW_LNS_set_basic_block: // No operands ++ DWARF_LOG_TRACE(" DW_LNS_set_basic_block"); ++ _state->_basic_block = true; ++ break; ++ case DW_LNS_const_add_pc: { // No operands ++ // Update address and op_index registers by the increments of special opcode 255. ++ uint8_t adjusted_opcode_255 = 255 - _header._opcode_base; ++ uint8_t operation_advance = adjusted_opcode_255 / _header._line_range; ++ uintptr_t old_address = _state->_address; ++ _state->add_to_address_register(operation_advance, _header); ++ if (_state->_dwarf_version == 4) { ++ _state->set_index_register(operation_advance, _header); ++ } ++ DWARF_LOG_TRACE(" DW_LNS_const_add_pc (" INTPTR_FORMAT ")", _state->_address - old_address); ++ break; ++ } ++ case DW_LNS_fixed_advance_pc: // 1 operand ++ uint16_t operand; ++ if (!_reader.read_word(&operand)) { ++ return false; ++ } ++ _state->_address += operand; ++ _state->_op_index = 0; ++ DWARF_LOG_TRACE(" DW_LNS_fixed_advance_pc (" INTPTR_FORMAT ")", _state->_address); ++ break; ++ case DW_LNS_set_prologue_end: // No operands ++ DWARF_LOG_TRACE(" DW_LNS_set_basic_block"); ++ _state->_prologue_end = true; ++ break; ++ case DW_LNS_set_epilogue_begin: // No operands ++ DWARF_LOG_TRACE(" DW_LNS_set_epilogue_begin"); ++ _state->_epilogue_begin = true; ++ break; ++ case DW_LNS_set_isa: // 1 operand ++ uint64_t isa; ++ if (!_reader.read_uleb128(&isa, 4)) { ++ // isa register is 4 bytes wide. ++ return false; ++ } ++ _state->_isa = isa; ++ DWARF_LOG_TRACE(" DW_LNS_set_isa (%u)", _state->_isa); ++ break; ++ default: ++ assert(false, "Unknown standard opcode"); ++ return false; ++ } ++ return true; ++} ++ ++// Specified in section 6.2.5.1 of the DWARF 4 spec. ++void DwarfFile::LineNumberProgram::apply_special_opcode(const uint8_t opcode) { ++ uintptr_t old_address = _state->_address; ++ uint32_t old_line = _state->_line; ++ uint8_t adjusted_opcode = opcode - _header._opcode_base; ++ uint8_t operation_advance = adjusted_opcode / _header._line_range; ++ _state->add_to_address_register(operation_advance, _header); ++ if (_state->_dwarf_version == 4) { ++ _state->set_index_register(operation_advance, _header); ++ _state->_discriminator = 0; ++ } ++ _state->_line += _header._line_base + (adjusted_opcode % _header._line_range); ++ DWARF_LOG_TRACE(" address += " INTPTR_FORMAT ", line += %d", _state->_address - old_address, ++ _state->_line - old_line); ++ _state->_append_row = true; ++ _state->_basic_block = false; ++ _state->_prologue_end = false; ++ _state->_epilogue_begin = false; ++} ++ ++bool DwarfFile::LineNumberProgram::does_offset_match_entry(const uintptr_t previous_address, const uint32_t previous_file, ++ const uint32_t previous_line) { ++ if (_state->_can_sequence_match_offset) { ++ bool matches_entry_directly = _offset_in_library == _state->_address; ++ if (matches_entry_directly ++ || (_offset_in_library > previous_address && _offset_in_library < _state->_address)) { // in between two entries ++ _state->_found_match = true; ++ if (!matches_entry_directly || _is_pc_after_call) { ++ // We take the previous row in the matrix either when: ++ // - We try to match an offset that is between two entries. ++ // - We have an offset from a PC that is at a call-site in which case we need to get the line information for ++ // the call instruction in the previous entry. ++ print_and_store_prev_entry(previous_file, previous_line); ++ return true; ++ } else if (!_reader.has_bytes_left()) { ++ // We take the current entry when this is the very last entry in the matrix (i.e. must be the right one). ++ DWARF_LOG_DEBUG("^^^ Found line for requested offset " PTR32_FORMAT " ^^^", _offset_in_library); ++ return true; ++ } ++ // Else: Exact match. We cannot take this entry because we do not know if there are more entries following this ++ // one with the same offset (we could have multiple entries for the same address in the matrix). Continue ++ // to parse entries. When we have the first non-exact match, then we know that the previous entry is the ++ // correct one to take (handled in the else-if-case below). If this is the very last entry in a matrix, ++ // we will take the current entry (handled in else-if-case above). ++ } else if (_state->_found_match) { ++ // We found an entry before with an exact match. This is now the first entry with a new offset. Pick the previous ++ // entry which matches our offset and is guaranteed to be the last entry which matches our offset (if there are ++ // multiple entries with the same offset). ++ print_and_store_prev_entry(previous_file, previous_line); ++ return true; ++ } ++ } ++ return false; ++} ++ ++void DwarfFile::LineNumberProgram::print_and_store_prev_entry(const uint32_t previous_file, const uint32_t previous_line) { ++ _state->_file = previous_file; ++ _state->_line = previous_line; ++ DWARF_LOG_DEBUG("^^^ Found line for requested offset " PTR32_FORMAT " ^^^", _offset_in_library); ++ // Also print the currently parsed entry. ++ DWARF_LOG_DEBUG(INTPTR_FORMAT " %-5u %-3u %-4u", ++ _state->_address, _state->_line, _state->_column, _state->_file); ++} ++ ++// Read field file_names from the header as specified in section 6.2.4 of the DWARF 4 spec. ++bool DwarfFile::LineNumberProgram::get_filename_from_header(const uint32_t file_index, char* filename, const size_t filename_len) { ++ // We do not need to restore the position afterwards as this is the last step of parsing from the file for this compilation unit. ++ _reader.set_position(_header._file_names_offset); ++ uint32_t current_index = 1; // file_names start at index 1 ++ while (_reader.has_bytes_left()) { ++ if (!_reader.read_string(filename, filename_len)) { ++ // Either an error while reading or we have reached the end of the file_names. Both should not happen. ++ return false; ++ } ++ ++ if (current_index == file_index) { ++ // Found correct file. ++ return true; ++ } ++ ++ // We don't care about these values. ++ if (!_reader.read_uleb128_ignore() // Read directory index ++ || !_reader.read_uleb128_ignore() // Read last modification of file ++ || !_reader.read_uleb128_ignore()) { // Read file length ++ return false; ++ } ++ current_index++; ++ } ++ DWARF_LOG_DEBUG("Did not find filename entry at index " UINT32_FORMAT " in .debug_line header", file_index); ++ return false; ++} ++ ++void DwarfFile::LineNumberProgram::LineNumberProgramState::reset_fields() { ++ _address = 0; ++ _op_index = 0; ++ _file = 1; ++ _line = 1; ++ _column = 0; ++ _is_stmt = _initial_is_stmt; ++ _basic_block = false; ++ _end_sequence = false; ++ _prologue_end = false; ++ _epilogue_begin = false; ++ _isa = 0; ++ _discriminator = 0; ++ _append_row = false; ++ _do_reset = false; ++ _first_entry_in_sequence = true; ++ _can_sequence_match_offset = false; ++} ++ ++// Defined in section 6.2.5.1 of the DWARF 4 spec. ++void DwarfFile::LineNumberProgram::LineNumberProgramState::add_to_address_register(const uint32_t operation_advance, ++ const LineNumberProgramHeader& header) { ++ if (_dwarf_version == 2 || _dwarf_version == 3) { ++ _address += (uintptr_t)(operation_advance * header._minimum_instruction_length); ++ } else if (_dwarf_version == 4) { ++ _address += (uintptr_t)(header._minimum_instruction_length * ++ ((_op_index + operation_advance) / header._maximum_operations_per_instruction)); ++ } ++} ++ ++// Defined in section 6.2.5.1 of the DWARF 4 spec. ++void DwarfFile::LineNumberProgram::LineNumberProgramState::set_index_register(const uint32_t operation_advance, ++ const LineNumberProgramHeader& header) { ++ _op_index = (_op_index + operation_advance) % header._maximum_operations_per_instruction; ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::set_position(const long new_pos) { ++ if (new_pos < 0) { ++ return false; ++ } ++ _current_pos = new_pos; ++ return FileReader::set_position(new_pos); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::has_bytes_left() const { ++ if (_max_pos == -1) { ++ return false; ++ } ++ return _current_pos < _max_pos; ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::update_to_stored_position() { ++ _marked_pos = ftell(_fd); ++ if (_marked_pos < 0) { ++ return false; ++ } ++ return FileReader::set_position(_current_pos); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::reset_to_previous_position() { ++ return FileReader::set_position(_marked_pos); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::move_position(const long offset) { ++ if (offset == 0) { ++ return true; ++ } ++ return set_position(_current_pos + offset); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::read_sbyte(int8_t* result) { ++ _current_pos++; ++ return read(result, 1); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::read_byte(uint8_t* result) { ++ _current_pos++; ++ return read(result, 1); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::read_word(uint16_t* result) { ++ _current_pos += 2; ++ return read(result, 2); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::read_dword(uint32_t* result) { ++ _current_pos += 4; ++ return read(result, 4); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::read_qword(uint64_t* result) { ++ _current_pos += 8; ++ return read(result, 8); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::read_address_sized(uintptr_t* result) { ++ _current_pos += DwarfFile::ADDRESS_SIZE; ++ return read(result, DwarfFile::ADDRESS_SIZE); ++} ++ ++// See Figure 46/47 in Appendix C of the DWARF 4 spec. ++bool DwarfFile::MarkedDwarfFileReader::read_leb128(uint64_t* result, const int8_t check_size, bool is_signed) { ++ *result = 0; // Ensure a proper result by zeroing it first. ++ uint8_t buf; ++ uint8_t shift = 0; ++ uint8_t bytes_read = 0; ++ // leb128 is not larger than 8 bytes. ++ while (bytes_read < 8) { ++ if (!read_byte(&buf)) { ++ return false; ++ } ++ bytes_read++; ++ *result |= (buf & 0x7fu) << shift; ++ shift += 7; ++ if ((buf & 0x80u) == 0) { ++ break; ++ } ++ } ++ if (bytes_read > 8 || (check_size != -1 && bytes_read > check_size)) { ++ // Invalid leb128 encoding or the read leb128 was larger than expected. ++ return false; ++ } ++ ++ if (is_signed && (shift < 64) && (buf & 0x40u)) { ++ *result |= static_cast(-1L) << shift; ++ } ++ return true; ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::read_uleb128_ignore(const int8_t check_size) { ++ uint64_t dont_care; ++ return read_leb128(&dont_care, check_size, false); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::read_uleb128(uint64_t* result, const int8_t check_size) { ++ return read_leb128(result, check_size, false); ++} ++ ++bool DwarfFile::MarkedDwarfFileReader::read_sleb128(int64_t* result, const int8_t check_size) { ++ return read_leb128((uint64_t*)result, check_size, true); ++} ++ ++// If result is a nullptr, we do not care about the content of the string being read. ++bool DwarfFile::MarkedDwarfFileReader::read_string(char* result, const size_t result_len) { ++ uint8_t next_byte; ++ if (!read_byte(&next_byte)) { ++ return false; ++ } ++ ++ if (next_byte == 0) { ++ // Strings must contain at least one non-null byte. ++ return false; ++ } ++ ++ if (result != NULL) { ++ if (result_len < 2) { ++ // Strings must contain at least one non-null byte and a null byte terminator. ++ return false; ++ } ++ result[0] = (char)next_byte; ++ } ++ ++ size_t char_index = 1; ++ bool exceeded_buffer = false; ++ while (has_bytes_left()) { ++ // Read until we find a null byte which terminates the string. ++ if (!read_byte(&next_byte)) { ++ return false; ++ } ++ ++ if (result != NULL) { ++ if (char_index >= result_len) { ++ // Exceeded buffer size of 'result'. ++ exceeded_buffer = true; ++ } else { ++ result[char_index] = (char)next_byte; ++ } ++ char_index++; ++ } ++ if (next_byte == 0) { ++ if (exceeded_buffer) { ++ result[result_len - 1] = '\0'; // Mark end of string. ++ DWARF_LOG_ERROR("Tried to read " SIZE_FORMAT " bytes but exceeded buffer size of " SIZE_FORMAT ". Truncating string.", ++ char_index, result_len); ++ } ++ return true; ++ } ++ } ++ return false; ++} ++ + #endif // !_WINDOWS && !__APPLE__ +diff --git a/hotspot/src/share/vm/utilities/elfFile.hpp b/hotspot/src/share/vm/utilities/elfFile.hpp +index 3ce8e92..3277a40 100644 +--- a/hotspot/src/share/vm/utilities/elfFile.hpp ++++ b/hotspot/src/share/vm/utilities/elfFile.hpp +@@ -36,6 +36,27 @@ + + #ifdef _LP64 + ++#ifdef ASSERT ++// Helper macros to print different log levels during DWARF parsing ++#define DWARF_LOG_SUMMARY(format, ...) DWARF_LOG_WITH_LEVEL(1, format, ##__VA_ARGS__) // Same level as error logging ++#define DWARF_LOG_ERROR(format, ...) DWARF_LOG_WITH_LEVEL(1, format, ##__VA_ARGS__) ++#define DWARF_LOG_INFO(format, ...) DWARF_LOG_WITH_LEVEL(2, format, ##__VA_ARGS__) ++#define DWARF_LOG_DEBUG(format, ...) DWARF_LOG_WITH_LEVEL(3, format, ##__VA_ARGS__) ++#define DWARF_LOG_TRACE(format, ...) DWARF_LOG_WITH_LEVEL(4, format, ##__VA_ARGS__) ++ ++#define DWARF_LOG_WITH_LEVEL(level, format, ...) \ ++ if (TraceDwarfLevel >= level) { \ ++ tty->print("[dwarf] "); \ ++ tty->print_cr(format, ##__VA_ARGS__); \ ++ } ++#else ++#define DWARF_LOG_SUMMARY(format, ...) ++#define DWARF_LOG_ERROR(format, ...) ++#define DWARF_LOG_INFO(format, ...) ++#define DWARF_LOG_DEBUG(format, ...) ++#define DWARF_LOG_TRACE(format, ...) ++#endif ++ + typedef Elf64_Half Elf_Half; + typedef Elf64_Word Elf_Word; + typedef Elf64_Off Elf_Off; +@@ -76,6 +97,29 @@ typedef Elf32_Sym Elf_Sym; + class ElfStringTable; + class ElfSymbolTable; + class ElfFuncDescTable; ++class DwarfFile; ++ ++class FileReader : public StackObj { ++ protected: ++ FILE* const _fd; ++ public: ++ FileReader(FILE* const fd) : _fd(fd) {}; ++ bool read(void* buf, size_t size); ++ size_t read_buffer(void* buf, size_t size); ++ virtual bool set_position(long offset); ++}; ++ ++// Mark current position, so we can get back to it after ++// reads. ++class MarkedFileReader : public FileReader { ++ protected: ++ long _marked_pos; ++ public: ++ MarkedFileReader(FILE* const fd); ++ ~MarkedFileReader(); ++ ++ bool has_mark() const { return _marked_pos >= 0; } ++}; + + + // On Solaris/Linux platforms, libjvm.so does contain all private symbols. +@@ -87,6 +131,34 @@ class ElfFuncDescTable; + + class ElfFile: public CHeapObj { + friend class ElfDecoder; ++ ++ protected: ++ ElfFile* m_next; ++ ++ private: ++ // file ++ const char* m_filepath; ++ FILE* m_file; ++ DwarfFile* m_dwarf_file; ++ ++ static const char* USR_LIB_DEBUG_DIRECTORY; ++ ++ // Elf header ++ Elf_Ehdr m_elfHdr; ++ ++ // symbol tables ++ ElfSymbolTable* m_symbol_tables; ++ ++ // string tables ++ ElfStringTable* m_string_tables; ++ ++ // function descriptors table ++ ElfFuncDescTable* m_funcDesc_table; ++ ++ NullDecoder::decoder_status m_status; ++ ++ ElfStringTable* m_shdr_string_table; ++ + public: + ElfFile(const char* filepath); + ~ElfFile(); +@@ -122,6 +194,9 @@ class ElfFile: public CHeapObj { + // return a string table at specified section index + ElfStringTable* get_string_table(int index); + ++ // Get filename and line number information ++ bool get_source_info(uint32_t offset_in_library, char* filename, size_t filename_len, int* line, bool is_pc_after_call); ++ + protected: + ElfFile* next() const { return m_next; } + void set_next(ElfFile* file) { m_next = file; } +@@ -134,27 +209,654 @@ protected: + // On systems other than linux it always returns false. + bool specifies_noexecstack() NOT_LINUX({ return false; }); + +- protected: +- ElfFile* m_next; + +- private: +- // file +- const char* m_filepath; +- FILE* m_file; ++ bool create_new_dwarf_file(const char* filepath); + +- // Elf header +- Elf_Ehdr m_elfHdr; ++ // Struct to store the debug info read from the .gnu_debuglink section. ++ struct DebugInfo { ++ static const uint8_t CRC_LEN = 4; + +- // symbol tables +- ElfSymbolTable* m_symbol_tables; ++ char _dwarf_filename[JVM_MAXPATHLEN]; ++ uint32_t _crc; ++ }; + +- // string tables +- ElfStringTable* m_string_tables; ++ // Helper class to create DWARF paths when loading a DWARF file. ++ class DwarfFilePath { ++ private: ++ static const uint16_t MAX_DWARF_PATH_LENGTH = JVM_MAXPATHLEN; ++ const char* _filename; ++ char _path[MAX_DWARF_PATH_LENGTH]; ++ const uint32_t _crc; ++ uint16_t _null_terminator_index; // Index for the current null terminator of the string stored in _path + +- // function descriptors table +- ElfFuncDescTable* m_funcDesc_table; ++ bool check_valid_path() const { ++ return _path[MAX_DWARF_PATH_LENGTH - 1] == '\0'; ++ } + +- NullDecoder::decoder_status m_status; ++ void update_null_terminator_index() { ++ _null_terminator_index = strlen(_path); ++ } ++ ++ bool copy_to_path_index(uint16_t index_in_path, const char* src); ++ ++ public: ++ DwarfFilePath(DebugInfo& debug_info) ++ : _filename(debug_info._dwarf_filename), _crc(debug_info._crc), _null_terminator_index(0) { ++ _path[MAX_DWARF_PATH_LENGTH - 1] = '\0'; // Ensures to have a null terminated string and not read beyond the buffer limit. ++ } ++ ++ const char* path() const { ++ return _path; ++ } ++ ++ const char* filename() const { ++ return _filename; ++ } ++ ++ uint32_t crc() const { ++ return _crc; ++ } ++ ++ bool set(const char* src); ++ ++ bool set_filename_after_last_slash() { ++ return set_after_last_slash(_filename); ++ } ++ ++ bool set_after_last_slash(const char* src); ++ bool append(const char* src); ++ }; ++ ++ // Load the DWARF file (.debuginfo) that belongs to this file either from (checked in listed order): ++ // - Same directory as the library file. ++ // - User defined path in environmental variable _JVM_DWARF_PATH. ++ // - Subdirectory .debug in same directory as the library file. ++ // - /usr/lib/debug directory ++ bool load_dwarf_file(); ++ ++ ++ bool read_debug_info(DebugInfo* debug_info) const; ++ ++ bool load_dwarf_file_from_same_directory(DwarfFilePath& dwarf_file_path); ++ bool load_dwarf_file_from_env_var_path(DwarfFilePath& dwarf_file_path); ++ bool load_dwarf_file_from_env_path_folder(DwarfFilePath& dwarf_file_path, const char* dwarf_path_from_env, const char* folder); ++ bool load_dwarf_file_from_debug_sub_directory(DwarfFilePath& dwarf_file_path); ++ bool load_dwarf_file_from_usr_lib_debug(DwarfFilePath& dwarf_file_path); ++ bool open_valid_debuginfo_file(const DwarfFilePath& dwarf_file_path); ++ static uint32_t get_file_crc(FILE* const file); ++ static uint gnu_debuglink_crc32(uint32_t crc, uint8_t* buf, size_t len); ++ ++ protected: ++ FILE* const fd() const { return m_file; } ++ ++ // Read the section header of section 'name'. ++ bool read_section_header(const char* name, Elf_Shdr& hdr) const; ++ bool is_valid_dwarf_file() const; ++}; ++ ++/* ++ * This class parses and reads filename and line number information from an associated .debuginfo file that belongs to ++ * this ELF file or directly from this ELF file if there is no separate .debuginfo file. The debug info is written by GCC ++ * in DWARF - a standardized debugging data format. There are special sections where the DWARF info is written to. These ++ * sections can either be put into the same ELF file or a separate .debuginfo file. For simplicity, when referring to the ++ * "DWARF file" or the ".debuginfo file" we just mean the file that contains the required DWARF sections. The current version ++ * of GCC uses DWARF version 4 as default which is defined in the official standard: http://www.dwarfstd.org/doc/DWARF4.pdf. ++ * This class is able to parse 32-bit DWARF version 4 for 32 and 64-bit Linux builds. GCC does not emit 64-bit DWARF and ++ * therefore is not supported by this parser. For some reason, GCC emits DWARF version 3 for the .debug_line section as a ++ * default. This parser was therefore adapted to support DWARF version 3 and 4 for the .debug_line section. Apart from that, ++ * other DWARF versions, especially the newest version 5, are not (yet) supported. ++ * ++ * Description of used DWARF file sections: ++ * - .debug_aranges: A table that consists of sets of variable length entries, each set describing the portion of the ++ * program's address space that is covered by a single compilation unit. In other words, the entries ++ * describe a mapping between addresses and compilation units. ++ * - .debug_info: The core DWARF data containing DWARF Information Entries (DIEs). Each DIE consists of a tag and a ++ * series of attributes. Each (normal) compilation unit is represented by a DIE with the tag ++ * DW_TAG_compile_unit and contains children. For our purposes, we are only interested in this DIE to ++ * get to the .debug_line section. We do not care about the children. This parser currently only ++ * supports normal compilation units and no partial compilation or type units. ++ * - .debug_abbrev: Represents abbreviation tables for all compilation units. A table for a specific compilation unit ++ * consists of a series of abbreviation declarations. Each declaration specifies a tag and attributes ++ * for a DIE. The DIEs from the compilation units in the .debug_info section need the abbreviation table ++ * to decode their attributes (their meaning and size). ++ * - .debug_line: Contains filename and line number information for each compilation unit. To get the information, a ++ * state machine needs to be executed which generates a matrix. Each row of this matrix describes the ++ * filename and line number (among other information) for a specific offset in the associated ELF library ++ * file. The state machine is executed until the row for the requested offset is found. The filename and ++ * line number information can then be fetched with the current register values of the state machine. ++ * ++ * Algorithm ++ * --------- ++ * Given: Offset into the ELF file library. ++ * Return: Filename and line number for this offset. ++ * (1) First, the path to the .debuginfo DWARF file is found by inspecting the .gnu_debuglink section of the library file. ++ * The DWARF file is then opened by calling the constructor of this class. Once this is done, the processing of the ++ * DWARF file is initiated by calling find_filename_and_line_number(). ++ * (2) Find the compilation unit offset by reading entries from the section .debug_aranges, which contain address range ++ * descriptors, until we find the correct descriptor that includes the library offset. ++ * (3) Find the .debug_line offset for the line number information program from the .debug_info section: ++ * (a) Parse the compilation unit header from the .debug_info section at the offset obtained by (2). ++ * (b) Read the debug_abbrev_offset into the .debug_abbrev section that belongs to this compilation unit from the ++ * header obtained in (3a). ++ * (c) Read the abbreviation code that immediately follows the compilation unit header from (3a) which is needed to ++ * find the correct entry in the .debug_abbrev section. ++ * (d) Find the correct entry in the abbreviation table in the .debug_abbrev section by starting to parse entries at ++ * the debug_abbrev_offset from (3b) until we find the correct one matching the abbreviation code from (3c). ++ * (e) Read the specified attributes of the abbreviation entry from (3d) from the compilation unit (in the .debug_info ++ * section) until we find the attribute DW_AT_stmt_list. This attributes represents an offset into the .debug_line ++ * section which contains the line number program information to get the filename and the line number. ++ * (4) Find the filename and line number belonging to the given library offset by running the line number program state ++ * machine with its registers. This creates a matrix where each row stores information for specific addresses (library ++ * offsets). The state machine executes different opcodes which modify the state machine registers. Certain opcodes ++ * will add a new row to the matrix by taking the current values of state machine registers. As soon as the correct ++ * matrix row matching the library offset is found, we can read the line number from the line register of the state ++ * machine and parse the filename from the line number program header with the given file index from the file register ++ * of the state machine. ++ * ++ * More details about the different phases can be found at the associated classes and methods. A visualization of the ++ * algorithm inside the different sections can be found in the class comments for DebugAranges, DebugAbbrev and ++ * LineNumberProgram further down in this file. ++ * ++ * Available (develop) log levels (-XX:TraceDwarfLevel=[1,4]) which are only present in debug builds. Each level prints ++ * all the logs of the previous levels and adds some more fine-grained logging: ++ * - Level 1 (summary + errors): ++ * - Prints the path of parsed DWARF file together with the resulting source information. ++ * - Prints all errors. ++ * - Level 2 (info): ++ * - Prints the found offsets of all DWARF sections ++ * - Level 3 (debug): ++ * - Prints the results of the steps (1) - (4) together with the generated line information matrix. ++ * - Level 4 (trace): ++ * - Complete information about intermediate states/results when parsing the DWARF file. ++ */ ++class DwarfFile : public ElfFile { ++ ++ static const uint8_t ADDRESS_SIZE = NOT_LP64(4) LP64_ONLY(8); ++ // We only support 32-bit DWARF (emitted by GCC) which uses 32-bit values for DWARF section lengths and offsets ++ // relative to the beginning of a section. ++ static const uint8_t DWARF_SECTION_OFFSET_SIZE = 4; ++ ++ class MarkedDwarfFileReader : public MarkedFileReader { ++ private: ++ long _current_pos; ++ long _max_pos; // Used to guarantee that we stop reading in case we reached the end of a section. ++ ++ bool read_leb128(uint64_t* result, int8_t check_size, bool is_signed); ++ public: ++ MarkedDwarfFileReader(FILE* const fd) : MarkedFileReader(fd), _current_pos(-1), _max_pos(-1) {} ++ ++ virtual bool set_position(long new_pos); ++ long get_position() const { return _current_pos; } ++ void set_max_pos(long max_pos) { _max_pos = max_pos; } ++ // Have we reached the limit of maximally allowable bytes to read? Used to ensure to stop reading when a section ends. ++ bool has_bytes_left() const; ++ // Call this if another file reader has changed the position of the same file handle. ++ bool update_to_stored_position(); ++ // Must be called to restore the old position before this file reader changed it with update_to_stored_position(). ++ bool reset_to_previous_position(); ++ bool move_position(long offset); ++ bool read_sbyte(int8_t* result); ++ bool read_byte(uint8_t* result); ++ bool read_word(uint16_t* result); ++ bool read_dword(uint32_t* result); ++ bool read_qword(uint64_t* result); ++ bool read_uleb128_ignore(int8_t check_size = -1); ++ bool read_uleb128(uint64_t* result, int8_t check_size = -1); ++ bool read_sleb128(int64_t* result, int8_t check_size = -1); ++ // Reads 4 bytes for 32-bit and 8 bytes for 64-bit builds. ++ bool read_address_sized(uintptr_t* result); ++ bool read_string(char* result = NULL, size_t result_len = 0); ++ }; ++ ++ // (2) Processing the .debug_aranges section to find the compilation unit which covers offset_in_library. ++ // This is specified in section 6.1.2 of the DWARF 4 spec. ++ // ++ // Structure of .debug_aranges: ++ // Section Header ++ // % Table of variable length sets describing the address space covered by a compilation unit ++ // % Set 1 ++ // ... ++ // % Set i: ++ // % Set header ++ // ... ++ // debug_info_offset -> offset to compilation unit ++ // % Series of address range descriptors [beginning_address, range_length]: ++ // % Descriptor 1 ++ // ... ++ // % Descriptor j: ++ // beginning_address <= offset_in_library < beginning_address + range_length? ++ // => Found the correct set covering offset_in_library. Take debug_info_offset from the set header to get ++ // to the correct compilation unit in .debug_info. ++ class DebugAranges { ++ ++ // The header is defined in section 6.1.2 of the DWARF 4 spec. ++ struct DebugArangesSetHeader { ++ // The total length of all of the entries for that set, not including the length field itself. ++ uint32_t _unit_length; ++ ++ // This number is specific to the address lookup table and is independent of the DWARF version number. ++ uint16_t _version; ++ ++ // The offset from the beginning of the .debug_info or .debug_types section of the compilation unit header referenced ++ // by the set. In this parser we only use it as offset into .debug_info. This must be 4 bytes for 32-bit DWARF. ++ uint32_t _debug_info_offset; ++ ++ // The size of an address in bytes on the target architecture, 4 bytes for 32-bit and 8 bytes for 64-bit Linux builds. ++ uint8_t _address_size; ++ ++ // The size of a segment selector in bytes on the target architecture. This should be 0. ++ uint8_t _segment_size; ++ }; ++ ++ // Address descriptor defining a range that is covered by a compilation unit. It is defined in section 6.1.2 after ++ // the set header in the DWARF 4 spec. ++ struct AddressDescriptor { ++ uintptr_t beginning_address; ++ uintptr_t range_length; ++ }; ++ ++ DwarfFile* _dwarf_file; ++ MarkedDwarfFileReader _reader; ++ uint32_t _section_start_address; ++ ++ bool read_section_header(); ++ bool read_set_header(DebugArangesSetHeader& header); ++ bool read_address_descriptors(uint32_t offset_in_library, bool& found_matching_set); ++ bool read_address_descriptor(AddressDescriptor& descriptor); ++ static bool does_match_offset(uint32_t offset_in_library, const AddressDescriptor& descriptor) ; ++ static bool is_terminating_entry(const AddressDescriptor& descriptor); ++ public: ++ DebugAranges(DwarfFile* dwarf_file) : _dwarf_file(dwarf_file), _reader(dwarf_file->fd()), _section_start_address(0) {} ++ bool find_compilation_unit_offset(uint32_t offset_in_library, uint32_t* compilation_unit_offset); ++ ++ }; ++ ++ // (3a-c,e) The compilation unit is read from the .debug_info section. The structure of .debug_info is shown in the ++ // comments of class DebugAbbrev. ++ class CompilationUnit { ++ ++ // Attribute form encodings from Figure 21 in section 7.5 of the DWARF 4 spec. ++ static const uint8_t DW_FORM_addr = 0x01; // address ++ static const uint8_t DW_FORM_block2 = 0x03; // block ++ static const uint8_t DW_FORM_block4 = 0x04; // block ++ static const uint8_t DW_FORM_data2 = 0x05; // constant ++ static const uint8_t DW_FORM_data4 = 0x06; // constant ++ static const uint8_t DW_FORM_data8 = 0x07; // constant ++ static const uint8_t DW_FORM_string = 0x08; // string ++ static const uint8_t DW_FORM_block = 0x09; // block ++ static const uint8_t DW_FORM_block1 = 0x0a; // block ++ static const uint8_t DW_FORM_data1 = 0x0b; // constant ++ static const uint8_t DW_FORM_flag = 0x0c; // flag ++ static const uint8_t DW_FORM_sdata = 0x0d; // constant ++ static const uint8_t DW_FORM_strp = 0x0e; // string ++ static const uint8_t DW_FORM_udata = 0x0f; // constant ++ static const uint8_t DW_FORM_ref_addr = 0x10; // reference0; ++ static const uint8_t DW_FORM_ref1 = 0x11; // reference ++ static const uint8_t DW_FORM_ref2 = 0x12; // reference ++ static const uint8_t DW_FORM_ref4 = 0x13; // reference ++ static const uint8_t DW_FORM_ref8 = 0x14; // reference ++ static const uint8_t DW_FORM_ref_udata = 0x15; // reference ++ static const uint8_t DW_FORM_indirect = 0x16; // see Section 7.5.3 ++ static const uint8_t DW_FORM_sec_offset = 0x17; // lineptr, loclistptr, macptr, rangelistptr ++ static const uint8_t DW_FORM_exprloc = 0x18; // exprloc ++ static const uint8_t DW_FORM_flag_present = 0x19; // flag ++ static const uint8_t DW_FORM_ref_sig8 = 0x20; // reference ++ ++ // The header is defined in section 7.5.1.1 of the DWARF 4 spec. ++ struct CompilationUnitHeader { ++ // The length of the .debug_info contribution for that compilation unit, not including the length field itself. ++ uint32_t _unit_length; ++ ++ // The version of the DWARF information for the compilation unit. The value in this field is 4 for DWARF 4. ++ uint16_t _version; ++ ++ // The offset into the .debug_abbrev section. This offset associates the compilation unit with a particular set of ++ // debugging information entry abbreviations. ++ uint32_t _debug_abbrev_offset; ++ ++ // The size in bytes of an address on the target architecture, 4 bytes for 32-bit and 8 bytes for 64-bit Linux builds. ++ uint8_t _address_size; ++ }; ++ ++ DwarfFile* _dwarf_file; ++ MarkedDwarfFileReader _reader; ++ CompilationUnitHeader _header; ++ const uint32_t _compilation_unit_offset; ++ ++ // Result of a request initiated by find_debug_line_offset(). ++ uint32_t _debug_line_offset; ++ ++ bool read_header(); ++ public: ++ CompilationUnit(DwarfFile* dwarf_file, uint32_t compilation_unit_offset) ++ : _dwarf_file(dwarf_file), _reader(dwarf_file->fd()), _compilation_unit_offset(compilation_unit_offset), _debug_line_offset(0) {} ++ ++ bool find_debug_line_offset(uint32_t* debug_line_offset); ++ bool read_attribute_value(uint64_t attribute_form, bool is_DW_AT_stmt_list_attribute); ++ }; ++ ++ // (3d) Read from the .debug_abbrev section at the debug_abbrev_offset specified by the compilation unit header. ++ // ++ // The interplay between the .debug_info and .debug_abbrev sections is more complex. The following visualization of the structure ++ // of both sections support the comments found in the parsing steps of the CompilationUnit and DebugAbbrev class. ++ // ++ // Structure of .debug_abbrev: ++ // Section Header ++ // % Series of abbreviation tables ++ // % Abbreviation table 1 ++ // ... ++ // % Abbreviation table for compilation unit at debug_abbrev_offset: ++ // % Series of declarations: ++ // % Declaration 1: ++ // abbreviation code ++ // tag ++ // DW_CHILDREN_yes/no ++ // % Series of attribute specifications ++ // % Attribute specification 1: ++ // attribute name ++ // attribute form ++ // ... ++ // % Last attribute specification: ++ // 0 ++ // 0 ++ // ... ++ // % Declaration i: ++ // Abbrev code read from compilation unit [AC] ++ // DW_TAG_compile_unit ++ // DW_CHILDREN_yes ++ // % Series of attribute specifications ++ // % Attribute specification 1 [AS1] ++ // ... ++ // % Attribute specification j [ASj]: ++ // DW_AT_stmt_list ++ // DW_FORM_sec_offset ++ // ++ // ++ // Structure of .debug_info: ++ // Section Header ++ // % Series of compilation units ++ // % Compilation unit 1 ++ // ... ++ // % Compilation unit i for library offset fetched from .debug_aranges: ++ // % Compilation unit header: ++ // ... ++ // debug_abbrev_offset -> offset for abbreviation table in .debug_abbrev for this compilation unit ++ // ... ++ // Abbrev code -> used in .debug_abbrev to find the correct declaration [AC] ++ // % Series of attribute values ++ // Attribute value 1 (in the format defined by attribute specification 1 [AS1]) ++ // ... ++ // Attribute value j (in the format defined by attribute specification j [ASj]): ++ // => Specifies Offset to line number program for this compilation unit in .debug_line ++ class DebugAbbrev { ++ ++ struct AbbreviationDeclaration { ++ uint64_t _abbrev_code; ++ uint64_t _tag; ++ uint8_t _has_children; ++ }; ++ ++ struct AttributeSpecification { ++ uint64_t _name; ++ uint64_t _form; ++ }; ++ ++ // Tag encoding from Figure 18 in section 7.5 of the DWARF 4 spec. ++ static const uint8_t DW_TAG_compile_unit = 0x11; ++ ++ // Child determination encoding from Figure 19 in section 7.5 of the DWARF 4 spec. ++ static const uint8_t DW_CHILDREN_yes = 0x01; ++ ++ // Attribute encoding from Figure 20 in section 7.5 of the DWARF 4 spec. ++ static const uint8_t DW_AT_stmt_list = 0x10; ++ ++ /* There is no specific header for this section */ ++ ++ DwarfFile* _dwarf_file; ++ MarkedDwarfFileReader _reader; ++ CompilationUnit* _compilation_unit; // Need to read from compilation unit while parsing the entries in .debug_abbrev. ++ ++ // Result field of a request ++ uint32_t* _debug_line_offset; ++ ++ bool read_declaration(AbbreviationDeclaration& declaration); ++ static bool is_wrong_or_unsupported_format(const AbbreviationDeclaration& declaration); ++ bool read_attribute_specifications(bool is_DW_TAG_compile_unit); ++ bool read_attribute_specification(AttributeSpecification& specification); ++ static bool is_terminating_specification(const AttributeSpecification& attribute_specification) ; ++ ++ public: ++ DebugAbbrev(DwarfFile* dwarf_file, CompilationUnit* compilation_unit) : ++ _dwarf_file(dwarf_file), _reader(_dwarf_file->fd()), _compilation_unit(compilation_unit), ++ _debug_line_offset(NULL) {} ++ ++ bool read_section_header(uint32_t debug_abbrev_offset); ++ bool find_debug_line_offset(uint64_t abbrev_code); ++ }; ++ ++ // (4) The line number program for the compilation unit at the offset of the .debug_line obtained by (3). ++ // For some reason, earlier GCC versions emit the line number program in DWARF 2 or 3 format even though the ++ // default is DWARF 4. It also mixes the standards (see comments in the parsing code). ++ // ++ // Therefore, this class supports DWARF 2, 3 and 4 parsing as specified in section 6.2 of the DWARF specs. ++ // The parsing of DWARF 2 is already covered by the parsing of DWARF 3 as they use the shared opcodes in the same way. ++ // The parsing of DWARF 4, however, needs some adaptation as it consumes more data for some shared opcodes. ++ // ++ // DWARF 2 standard: https://dwarfstd.org/doc/dwarf-2.0.0.pdf ++ // DWARF 3 standard: https://dwarfstd.org/doc/Dwarf3.pdf ++ // ++ // ++ // Structure of .debug_ling: ++ // Section Header ++ // % Series of line number program entries for each compilation unit ++ // % Line number program 1 ++ // ... ++ // % Line number program i for our compilation unit: ++ // % Line program header unit header: ++ // ... ++ // version -> currently emits version 3 by default ++ // ... ++ // file_name -> sequence of file names ++ // % Sequence of opcodes as part of the line number program to build the line number information matrix: ++ // % Format of matrix: [offset, line, directory_index, file_index] ++ // % Line 1 ++ // ... ++ // % Line j: ++ // [offset matching offset_in_library, line, directory_index, file_index] ++ // => Get line number + look up file_index in file_name list (pick file_index'th string) ++ class LineNumberProgram { ++ ++ // Standard opcodes for the line number program defined in section 6.2.5.2 of the DWARF 4 spec. ++ static const uint8_t DW_LNS_copy = 1; ++ static const uint8_t DW_LNS_advance_pc = 2; ++ static const uint8_t DW_LNS_advance_line = 3; ++ static const uint8_t DW_LNS_set_file = 4; ++ static const uint8_t DW_LNS_set_column = 5; ++ static const uint8_t DW_LNS_negate_stmt = 6; ++ static const uint8_t DW_LNS_set_basic_block = 7; ++ static const uint8_t DW_LNS_const_add_pc = 8; ++ static const uint8_t DW_LNS_fixed_advance_pc = 9; ++ static const uint8_t DW_LNS_set_prologue_end = 10; // Introduced with DWARF 3 ++ static const uint8_t DW_LNS_set_epilogue_begin = 11; // Introduced with DWARF 3 ++ static const uint8_t DW_LNS_set_isa = 12; // Introduced with DWARF 3 ++ ++ // Extended opcodes for the line number program defined in section 6.2.5.2 of the DWARF 4 spec. ++ static const uint8_t DW_LNE_end_sequence = 1; ++ static const uint8_t DW_LNE_set_address = 2; ++ static const uint8_t DW_LNE_define_file = 3; ++ static const uint8_t DW_LNE_set_discriminator = 4; // Introduced with DWARF 4 ++ ++ // The header is defined in section 6.2.4 of the DWARF 4 spec. ++ struct LineNumberProgramHeader { ++ // The size in bytes of the line number information for this compilation unit, not including the unit_length ++ // field itself. 32-bit DWARF uses 4 bytes. ++ uint32_t _unit_length; ++ ++ // The version of the DWARF information for the line number program unit. The value in this field should be 4 for ++ // DWARF 4 and version 3 as used for DWARF 3. ++ uint16_t _version; ++ ++ // The number of bytes following the header_length field to the beginning of the first byte of the line number ++ // program itself. 32-bit DWARF uses 4 bytes. ++ uint32_t _header_length; ++ ++ // The size in bytes of the smallest target machine instruction. Line number program opcodes that alter the address ++ // and op_index registers use this and maximum_operations_per_instruction in their calculations. ++ uint8_t _minimum_instruction_length; ++ ++ // The maximum number of individual operations that may be encoded in an instruction. Line number program opcodes ++ // that alter the address and op_index registers use this and minimum_instruction_length in their calculations. ++ // For non-VLIW architectures, this field is 1, the op_index register is always 0, and the operation pointer is ++ // simply the address register. This is only used with DWARF 4. ++ uint8_t _maximum_operations_per_instruction; ++ ++ // The initial value of the is_stmt register. ++ uint8_t _default_is_stmt; ++ ++ // This parameter affects the meaning of the special opcodes. ++ int8_t _line_base; ++ ++ // This parameter affects the meaning of the special opcodes. ++ uint8_t _line_range; ++ ++ // The number assigned to the first special opcode. ++ uint8_t _opcode_base; ++ ++ // This array specifies the number of LEB128 operands for each of the standard opcodes. The first element of the ++ // array corresponds to the opcode whose value is 1, and the last element corresponds to the opcode whose value is ++ // opcode_base-1. DWARF 2 uses 9 standard opcodes while DWARF 3 and 4 use 12. ++ uint8_t _standard_opcode_lengths[12]; ++ ++ /* ++ * The following fields are not part of the real header and are only used for the implementation. ++ */ ++ // Offset where the filename strings are starting in header. ++ long _file_names_offset; ++ ++ // _header_length only specifies the number of bytes following the _header_length field. It does not include ++ // the size of _unit_length, _version and _header_length itself. This constant represents the number of missing ++ // bytes to get the real size of the header: ++ // sizeof(_unit_length) + sizeof(_version) + sizeof(_header_length) = 4 + 2 + 4 = 10 ++ static const uint8_t HEADER_DESCRIPTION_BYTES = 10; ++ }; ++ ++ // The line number program state consists of several registers that hold the current state of the line number program ++ // state machine. The state/different state registers are defined in section 6.2.2 of the DWARF 4 spec. Most of these ++ // fields (state registers) are not used to get the filename and the line number information. ++ struct LineNumberProgramState : public CHeapObj { ++ // The program-counter value corresponding to a machine instruction generated by the compiler. ++ // 4 bytes on 32-bit and 8 bytes on 64-bit. ++ uintptr_t _address; ++ ++ // The index of an operation within a VLIW instruction. The index of the first operation is 0. For non-VLIW ++ // architectures, this register will always be 0. ++ // The address and op_index registers, taken together, form an operation pointer that can reference any ++ // individual operation with the instruction stream. This field was introduced with DWARF 4. ++ uint32_t _op_index; ++ ++ // The identity of the source file corresponding to a machine instruction. ++ uint32_t _file; ++ ++ // A source line number. Lines are numbered beginning at 1. The compiler may emit the value 0 in cases where an ++ // instruction cannot be attributed to any source line. ++ uint32_t _line; ++ ++ // A column number within a source line. Columns are numbered beginning at 1. The value 0 is reserved to indicate ++ // that a statement begins at the “left edge” of the line. ++ uint32_t _column; ++ ++ // Indicates that the current instruction is a recommended breakpoint location. ++ bool _is_stmt; ++ ++ // Indicates that the current instruction is the beginning of a basic block. ++ bool _basic_block; ++ ++ // Indicates that the current address is that of the first byte after the end of a sequence of target machine ++ // instructions. end_sequence terminates a sequence of lines. ++ bool _end_sequence; ++ ++ // Indicates that the current address is one (of possibly many) where execution should be suspended for an entry ++ // breakpoint of a function. This field was introduced with DWARF 3. ++ bool _prologue_end; ++ ++ // Indicates that the current address is one (of possibly many) where execution should be suspended for an exit ++ // breakpoint of a function. This field was introduced with DWARF 3. ++ bool _epilogue_begin; ++ ++ // Encodes the applicable instruction set architecture for the current instruction. ++ // This field was introduced with DWARF 3. ++ uint32_t _isa; ++ ++ // Identifies the block to which the current instruction belongs. This field was introduced with DWARF 4. ++ uint32_t _discriminator; ++ ++ /* ++ * Additional fields which are not part of the actual state as described in DWARF spec. ++ */ ++ // Header fields ++ // Specifies which DWARF version is used in the .debug_line section. Supported version: DWARF 2, 3, and 4. ++ const uint16_t _dwarf_version; ++ const bool _initial_is_stmt; ++ ++ // Implementation specific fields ++ bool _append_row; ++ bool _do_reset; ++ bool _first_entry_in_sequence; ++ bool _can_sequence_match_offset; ++ bool _found_match; ++ ++ LineNumberProgramState(const LineNumberProgramHeader& header) ++ : _is_stmt(header._default_is_stmt != 0), _dwarf_version(header._version), ++ _initial_is_stmt(header._default_is_stmt != 0), _found_match(false) { ++ reset_fields(); ++ } ++ ++ void reset_fields(); ++ // Defined in section 6.2.5.1 of the DWARF spec 4. add_to_address_register() must always be executed before set_index_register. ++ void add_to_address_register(uint32_t operation_advance, const LineNumberProgramHeader& header); ++ void set_index_register(uint32_t operation_advance, const LineNumberProgramHeader& header); ++ }; ++ ++ DwarfFile* _dwarf_file; ++ MarkedDwarfFileReader _reader; ++ LineNumberProgramHeader _header; ++ LineNumberProgramState* _state; ++ const uint32_t _offset_in_library; ++ const uint64_t _debug_line_offset; ++ bool _is_pc_after_call; ++ ++ bool read_header(); ++ bool run_line_number_program(char* filename, size_t filename_len, int* line); ++ bool apply_opcode(); ++ bool apply_extended_opcode(); ++ bool apply_standard_opcode(uint8_t opcode); ++ void apply_special_opcode(const uint8_t opcode); ++ bool does_offset_match_entry(uintptr_t previous_address, uint32_t previous_file, uint32_t previous_line); ++ void print_and_store_prev_entry(uint32_t previous_file, uint32_t previous_line); ++ bool get_filename_from_header(uint32_t file_index, char* filename, size_t filename_len); ++ ++ public: ++ LineNumberProgram(DwarfFile* dwarf_file, uint32_t offset_in_library, uint64_t debug_line_offset, bool is_pc_after_call) ++ : _dwarf_file(dwarf_file), _reader(dwarf_file->fd()), _offset_in_library(offset_in_library), ++ _debug_line_offset(debug_line_offset), _is_pc_after_call(is_pc_after_call) {} ++ ++ bool find_filename_and_line_number(char* filename, size_t filename_len, int* line); ++ }; ++ ++ public: ++ DwarfFile(const char* filepath) : ElfFile(filepath) {} ++ ++ /* ++ * Starting point of reading line number and filename information from the DWARF file. ++ * ++ * Given: Offset into the ELF library file, a filename buffer of size filename_size, a line number pointer. ++ * Return: True: The filename is set in the 'filename' buffer and the line number at the address pointed to by 'line'. ++ * False: Something went wrong either while reading from the file or during parsing due to an unexpected format. ++ * This could happen if the DWARF file is in an unsupported or wrong format. ++ * ++ * More details about the different phases can be found at the associated methods. ++ */ ++ bool get_filename_and_line_number(uint32_t offset_in_library, char* filename, size_t filename_len, int* line, bool is_pc_after_call); + }; + + #endif // !_WINDOWS && !__APPLE__ +diff --git a/hotspot/src/share/vm/utilities/nativeCallStack.cpp b/hotspot/src/share/vm/utilities/nativeCallStack.cpp +index ee6eb31..6b18b49 100644 +--- a/hotspot/src/share/vm/utilities/nativeCallStack.cpp ++++ b/hotspot/src/share/vm/utilities/nativeCallStack.cpp +@@ -24,6 +24,7 @@ + + #include "precompiled.hpp" + #include "runtime/os.hpp" ++#include "utilities/decoder.hpp" + #include "utilities/globalDefinitions.hpp" + #include "utilities/nativeCallStack.hpp" + +@@ -93,6 +94,8 @@ void NativeCallStack::print_on(outputStream* out, int indent) const { + address pc; + char buf[1024]; + int offset; ++ int line_no; ++ + if (is_empty()) { + for (int index = 0; index < indent; index ++) out->print(" "); + #if PLATFORM_NATIVE_STACK_WALKING_SUPPORTED +@@ -107,10 +110,14 @@ void NativeCallStack::print_on(outputStream* out, int indent) const { + // Print indent + for (int index = 0; index < indent; index ++) out->print(" "); + if (os::dll_address_to_function_name(pc, buf, sizeof(buf), &offset)) { +- out->print_cr("[" PTR_FORMAT "] %s+0x%x", p2i(pc), buf, offset); ++ out->print("[" PTR_FORMAT "] %s+0x%x", p2i(pc), buf, offset); + } else { +- out->print_cr("[" PTR_FORMAT "]", p2i(pc)); ++ out->print("[" PTR_FORMAT "]", p2i(pc)); ++ } ++ if (Decoder::get_source_info(pc, buf, sizeof(buf), &line_no, frame != 0)) { ++ out->print(" (%s:%d)", buf, line_no); + } ++ out->cr(); + } + } + } +diff --git a/hotspot/src/share/vm/utilities/vmError.cpp b/hotspot/src/share/vm/utilities/vmError.cpp +index 261591d..26408fa 100644 +--- a/hotspot/src/share/vm/utilities/vmError.cpp ++++ b/hotspot/src/share/vm/utilities/vmError.cpp +@@ -1209,3 +1209,9 @@ void VMError::report_java_out_of_memory() { + VMThread::execute(&op); + } + } ++ ++// Returns true if the current thread reported a fatal error. ++bool VMError::is_error_reported_in_current_thread() { ++ return first_error_tid == os::current_thread_id(); ++} ++ +diff --git a/hotspot/src/share/vm/utilities/vmError.hpp b/hotspot/src/share/vm/utilities/vmError.hpp +index 299cfaa..21db84d 100644 +--- a/hotspot/src/share/vm/utilities/vmError.hpp ++++ b/hotspot/src/share/vm/utilities/vmError.hpp +@@ -140,6 +140,9 @@ public: + static jlong get_first_error_tid() { + return first_error_tid; + } ++ ++ // Returns true if the current thread reported a fatal error. ++ static bool is_error_reported_in_current_thread(); + }; + + #endif // SHARE_VM_UTILITIES_VMERROR_HPP +diff --git a/jdk/test/jdk/java/dwarf/TestDwarf.java b/jdk/test/jdk/java/dwarf/TestDwarf.java +new file mode 100644 +index 0000000..8e41a28 +--- /dev/null ++++ b/jdk/test/jdk/java/dwarf/TestDwarf.java +@@ -0,0 +1,240 @@ ++/* ++ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * 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 8242181 ++ * @library ../../../lib/ ../../../lib/testlibrary ++ * @summary Test DWARF parser with various crashes if debug symbols are available. If the libjvm debug symbols are not ++ * in the same directory as the libjvm.so file, in a subdirectory called .debug, or in the path specified ++ * by the environment variable _JVM_DWARF_PATH, then no verification of the hs_err_file is done for libjvm.so. ++ * @requires vm.compMode != "Xint" & os.family == "linux" ++ * @run main/othervm TestDwarf ++ */ ++ ++import jdk.test.lib.Asserts; ++import jdk.test.lib.Platform; ++import jdk.testlibrary.OutputAnalyzer; ++import jdk.testlibrary.ProcessTools; ++ ++import sun.misc.Unsafe; ++ ++import java.io.BufferedReader; ++import java.io.File; ++import java.io.FileReader; ++import java.lang.reflect.Field; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.List; ++import java.util.regex.Matcher; ++import java.util.regex.Pattern; ++ ++public class TestDwarf { ++ public static void main(String[] args) throws Throwable { ++ if (args.length != 0) { ++ switch (args[0]) { ++ case "outOfMemory" : ++ crashOutOfMemory(); ++ Asserts.fail("Should crash in crashOutOfMemory()"); ++ case "abortVMOnException" : ++ crashAbortVmOnException(); ++ Asserts.fail("Should crash in crashAbortVmOnException()"); ++ } ++ } else { ++ try { ++ test(); ++ } catch (UnsupportedDwarfVersionException e) { ++ System.out.println("Skip test due to a DWARF section that is in an unsupported version by the parser."); ++ } ++ } ++ } ++ ++ // Crash the VM in different ways in order to verify that DWARF parsing is able to print the source information ++ // in the hs_err_files for each VM and C stack frame. ++ private static void test() throws Throwable { ++ runAndCheck(new Flags("-Xcomp", "-XX:CICrashAt=1", "-version")); ++ runAndCheck(new Flags("-Xmx100M", "-XX:ErrorHandlerTest=15", "-version")); ++ runAndCheck(new Flags("-XX:+CrashGCForDumpingJavaThread", "-version")); ++ runAndCheck(new Flags("-Xmx10m", "-XX:+CrashOnOutOfMemoryError", TestDwarf.class.getCanonicalName(), "outOfMemory")); ++ // Use -XX:-TieredCompilation as C1 is currently not aborting the VM (JDK-8264899). ++ runAndCheck(new Flags("-XX:-TieredCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:AbortVMOnException=MyException", ++ TestDwarf.class.getCanonicalName(), "abortVMOnException")); ++ if (Platform.isX64() || Platform.isX86()) { ++ // Not all platforms raise SIGFPE but x86_32 and x86_64 do. ++ } ++ } ++ ++ private static void runAndCheck(Flags flags, DwarfConstraint... constraints) throws Throwable { ++ OutputAnalyzer crashOut; ++ ProcessBuilder pb; ++ int flag_size = flags.getFlags().size(); ++ pb = ProcessTools.createJavaProcessBuilder(flags.getFlags().toArray(new String[flag_size])); ++ crashOut = ProcessTools.executeProcess(pb); ++ String crashOutputString = crashOut.getOutput(); ++ Asserts.assertNotEquals(crashOut.getExitValue(), 0, "Crash JVM should not exit gracefully"); ++ Pattern pattern = Pattern.compile("hs_err_pid[0-9]*.log"); ++ Matcher matcher = pattern.matcher(crashOutputString); ++ System.out.println(crashOutputString); ++ if (matcher.find()) { ++ String hsErrFileName = matcher.group(); ++ System.out.println("hs_err_file: " + hsErrFileName); ++ File hs_err_file = new File(hsErrFileName); ++ BufferedReader reader = new BufferedReader(new FileReader(hs_err_file)); ++ String line; ++ boolean foundNativeFrames = false; ++ int matches = 0; ++ int frameIdx = 0; ++ // Check all stack entries after the line starting with "Native frames" in the hs_err_file until an empty line ++ // is found which denotes the end of the stack frames. ++ while ((line = reader.readLine()) != null) { ++ if (foundNativeFrames) { ++ if (line.isEmpty()) { ++ // Done with the entire stack. ++ break; ++ } else if ((line.startsWith("C") || line.startsWith("V"))) { ++ // Could be VM or native C frame. There are usually no symbols available for libpthread.so. ++ matches++; ++ // File and library names are non-empty and may contain English letters, underscores, dots or numbers ([a-zA-Z0-9_.]+). ++ // Line numbers have at least one digit and start with non-zero ([1-9][0-9]*). ++ pattern = Pattern.compile("[CV][\\s\\t]+\\[([a-zA-Z0-9_.]+)\\+0x.+][\\s\\t]+.*\\+0x.+[\\s\\t]+\\([a-zA-Z0-9_.]+\\.[a-z]+:[1-9][0-9]*\\)"); ++ matcher = pattern.matcher(line); ++ if (!matcher.find()) { ++ checkNoSourceLine(crashOutputString, line); ++ } ++ ++ // Check additional DWARF constraints ++ if (constraints != null) { ++ int finalFrameIdx = frameIdx; ++ String finalLine = line; ++ Arrays.stream(constraints).forEach(c -> c.checkConstraint(finalFrameIdx, finalLine)); ++ } ++ } ++ frameIdx++; ++ } else if (line.startsWith("Native frames")) { ++ // Stack starts after this line. ++ foundNativeFrames = true; ++ } ++ } ++ Asserts.assertGreaterThan(matches, 0, "Could not find any stack frames"); ++ } else { ++ throw new RuntimeException("Could not find an hs_err_file"); ++ } ++ } ++ ++ /** ++ * There are some valid cases where we cannot find source information. Check these. ++ */ ++ private static void checkNoSourceLine(String crashOutputString, String line) { ++ Pattern pattern = Pattern.compile("[CV][\\s\\t]+\\[([a-zA-Z0-9_.]+)\\+0x.+][\\s\\t]+.*\\+0x"); ++ Matcher matcher = pattern.matcher(line); ++ Asserts.assertTrue(matcher.find(), "Must find library in \"" + line + "\""); ++ // Check if there are symbols available for library. If not, then we cannot find any source information for this library. ++ // This can happen if this test is run without any JDK debug symbols at all but also for some libraries like libpthread.so ++ // which usually has no symbols available. ++ String library = matcher.group(1); ++ pattern = Pattern.compile("Failed to load DWARF file for library.*" + library + ".*or find DWARF sections directly inside it"); ++ matcher = pattern.matcher(crashOutputString); ++ if (!matcher.find()) { ++ bailoutIfUnsupportedDwarfVersion(crashOutputString); ++ throw new RuntimeException("Could not find filename or line number in \"" + line + "\""); ++ } ++ // We should always find symbols for libTestDwarf.so. ++ Asserts.assertFalse(library.equals("libTestDwarf.so"), "Could not find filename or line number in \"" + line + "\" for libTestDwarf.so"); ++ System.out.println("Did not find symbols for " + library + ". If they are not in the same directory as " + library + " consider setting " + ++ "the environmental variable _JVM_DWARF_PATH to point to the debug symbols directory."); ++ } ++ ++ /** ++ * Some older GCC versions might emit DWARF sections in an old format that is not supported by the DWARF parser. ++ * If this is the case, skip this entire test by throwing UnsupportedDwarfVersionException. ++ */ ++ private static void bailoutIfUnsupportedDwarfVersion(String crashOutputString) { ++ Pattern pattern = Pattern.compile(".debug_\\S+ in unsupported DWARF version \\d+"); ++ Matcher matcher = pattern.matcher(crashOutputString); ++ if (matcher.find()) { ++ throw new UnsupportedDwarfVersionException(); ++ } ++ } ++ ++ // Crash with SIGSEGV. ++ private static void crashUnsafeAccess() throws Exception { ++ Field f = Unsafe.class.getDeclaredField("theUnsafe"); ++ f.setAccessible(true); ++ Unsafe unsafe = (Unsafe)f.get(null); ++ unsafe.putAddress(0, 0); // Crash ++ } ++ ++ // Crash with Internal Error: Java heap space. ++ private static void crashOutOfMemory() { ++ Object[] o = null; ++ ++ // Loop endlessly and consume memory until we run out. Will crash due to -XX:+CrashOnOutOfMemoryError. ++ while (true) { ++ o = new Object[] {o}; ++ } ++ } ++ ++ // Crash with Internal Error: Saw java.lang.RuntimeException, aborting. ++ // Crash happens due to an exception raised in combination with -XX:AbortVMOnException. ++ private static void crashAbortVmOnException() { ++ throw new MyException(); ++ } ++} ++ ++class UnsupportedDwarfVersionException extends RuntimeException { } ++ ++class MyException extends RuntimeException { } ++ ++class Flags { ++ private final List listOfOptions = new ArrayList<>(); ++ ++ Flags(String... flags) { ++ listOfOptions.add("-XX:TraceDwarfLevel=2"); // Always add debug flag ++ listOfOptions.addAll(Arrays.asList(flags)); ++ } ++ ++ public List getFlags() { ++ return listOfOptions; ++ } ++ ++} ++class DwarfConstraint { ++ private final int frameIdx; ++ private final String methodName; ++ private final String dwarfInfo; ++ ++ DwarfConstraint(int frameIdx, String methodName, String fileName, int lineNo) { ++ this.frameIdx = frameIdx; ++ this.methodName = methodName; ++ this.dwarfInfo = "(" + fileName + ":" + lineNo + ")"; ++ } ++ ++ public void checkConstraint(int currentFrameIdx, String line) { ++ if (frameIdx == currentFrameIdx) { ++ Asserts.assertTrue(line.contains(methodName), "Could not find method name " + methodName + " in \"" + line + "\""); ++ Asserts.assertTrue(line.contains(dwarfInfo) , "Could not find DWARF info " + dwarfInfo + " in \"" + line + "\""); ++ } ++ } ++} ++ +-- +1.8.3.1 diff --git a/8257695-linux-Add-process-memory-information-to-hs-e.patch b/8257695-linux-Add-process-memory-information-to-hs-e.patch new file mode 100644 index 0000000..7cd83f4 --- /dev/null +++ b/8257695-linux-Add-process-memory-information-to-hs-e.patch @@ -0,0 +1,123 @@ +From d68c637a36b65d0bce893991e9c910efbc06239a Mon Sep 17 00:00:00 2001 +From: eapen +Date: Mon, 12 Dec 2022 16:10:41 +0800 +Subject: [PATCH 10/33] I68TO2: 8257695: [linux] Add process-memory information to + hs-err and VM.info +--- + hotspot/src/os/linux/vm/os_linux.cpp | 67 ++++++++++++++++++++++++++++++++++-- + hotspot/src/os/linux/vm/os_linux.hpp | 3 +- + 2 files changed, 67 insertions(+), 3 deletions(-) + +diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp +index 6dbedf5..4c265d5 100644 +--- a/hotspot/src/os/linux/vm/os_linux.cpp ++++ b/hotspot/src/os/linux/vm/os_linux.cpp +@@ -103,6 +103,9 @@ + # include + # include + # include ++#ifdef __GLIBC__ ++# include ++#endif + + PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC + +@@ -2216,7 +2219,10 @@ void os::print_os_info(outputStream* st) { + + os::Posix::print_load_average(st); + +- os::Linux::print_full_memory_info(st); ++ os::Linux::print_system_memory_info(st); ++ st->cr(); ++ ++ os::Linux::print_process_memory_info(st); + + os::Linux::print_container_info(st); + } +@@ -2278,12 +2284,69 @@ void os::Linux::print_libversion_info(outputStream* st) { + st->cr(); + } + +-void os::Linux::print_full_memory_info(outputStream* st) { ++void os::Linux::print_system_memory_info(outputStream* st) { + st->print("\n/proc/meminfo:\n"); + _print_ascii_file("/proc/meminfo", st); + st->cr(); + } + ++void os::Linux::print_process_memory_info(outputStream* st) { ++ ++ st->print_cr("Process Memory:"); ++ ++ // Print virtual and resident set size; peak values; swap; and for ++ // rss its components if the kernel is recent enough. ++ ssize_t vmsize = -1, vmpeak = -1, vmswap = -1, ++ vmrss = -1, vmhwm = -1, rssanon = -1, rssfile = -1, rssshmem = -1; ++ const int num_values = 8; ++ int num_found = 0; ++ FILE* f = ::fopen("/proc/self/status", "r"); ++ char buf[256]; ++ while (::fgets(buf, sizeof(buf), f) != NULL && num_found < num_values) { ++ if ( (vmsize == -1 && sscanf(buf, "VmSize: " SSIZE_FORMAT " kB", &vmsize) == 1) || ++ (vmpeak == -1 && sscanf(buf, "VmPeak: " SSIZE_FORMAT " kB", &vmpeak) == 1) || ++ (vmswap == -1 && sscanf(buf, "VmSwap: " SSIZE_FORMAT " kB", &vmswap) == 1) || ++ (vmhwm == -1 && sscanf(buf, "VmHWM: " SSIZE_FORMAT " kB", &vmhwm) == 1) || ++ (vmrss == -1 && sscanf(buf, "VmRSS: " SSIZE_FORMAT " kB", &vmrss) == 1) || ++ (rssanon == -1 && sscanf(buf, "RssAnon: " SSIZE_FORMAT " kB", &rssanon) == 1) || ++ (rssfile == -1 && sscanf(buf, "RssFile: " SSIZE_FORMAT " kB", &rssfile) == 1) || ++ (rssshmem == -1 && sscanf(buf, "RssShmem: " SSIZE_FORMAT " kB", &rssshmem) == 1) ++ ) ++ { ++ num_found ++; ++ } ++ } ++ st->print_cr("Virtual Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", vmsize, vmpeak); ++ st->print("Resident Set Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", vmrss, vmhwm); ++ if (rssanon != -1) { // requires kernel >= 4.5 ++ st->print(" (anon: " SSIZE_FORMAT "K, file: " SSIZE_FORMAT "K, shmem: " SSIZE_FORMAT "K)", ++ rssanon, rssfile, rssshmem); ++ } ++ st->cr(); ++ if (vmswap != -1) { // requires kernel >= 2.6.34 ++ st->print_cr("Swapped out: " SSIZE_FORMAT "K", vmswap); ++ } ++ ++ // Print glibc outstanding allocations. ++ // (note: there is no implementation of mallinfo for muslc) ++#ifdef __GLIBC__ ++ struct mallinfo mi = ::mallinfo(); ++ ++ // mallinfo is an old API. Member names mean next to nothing and, beyond that, are int. ++ // So values may have wrapped around. Still useful enough to see how much glibc thinks ++ // we allocated. ++ const size_t total_allocated = (size_t)(unsigned)mi.uordblks; ++ st->print("C-Heap outstanding allocations: " SIZE_FORMAT "K", total_allocated / K); ++ // Since mallinfo members are int, glibc values may have wrapped. Warn about this. ++ if ((vmrss * K) > UINT_MAX && (vmrss * K) > (total_allocated + UINT_MAX)) { ++ st->print(" (may have wrapped)"); ++ } ++ st->cr(); ++ ++#endif // __GLIBC__ ++ ++} ++ + void os::Linux::print_container_info(outputStream* st) { + if (!OSContainer::is_containerized()) { + return; +diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp +index c674882..066b03a 100644 +--- a/hotspot/src/os/linux/vm/os_linux.hpp ++++ b/hotspot/src/os/linux/vm/os_linux.hpp +@@ -120,7 +120,8 @@ class Linux { + static bool release_memory_special_shm(char* base, size_t bytes); + static bool release_memory_special_huge_tlbfs(char* base, size_t bytes); + +- static void print_full_memory_info(outputStream* st); ++ static void print_process_memory_info(outputStream* st); ++ static void print_system_memory_info(outputStream* st); + static void print_container_info(outputStream* st); + static void print_distro_info(outputStream* st); + static void print_libversion_info(outputStream* st); +-- +1.8.3.1 diff --git a/8261167-print_process_memory_info-add-a-close-call-a.patch b/8261167-print_process_memory_info-add-a-close-call-a.patch new file mode 100644 index 0000000..80142d9 --- /dev/null +++ b/8261167-print_process_memory_info-add-a-close-call-a.patch @@ -0,0 +1,73 @@ +From 959f2dfd0868274f202c313a24784b0be8da3d32 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Mon, 12 Dec 2022 17:00:02 +0800 +Subject: [PATCH 11/33] I68TO2: 8261167: print_process_memory_info add a close call + after fopen +--- + hotspot/src/os/linux/vm/os_linux.cpp | 50 ++++++++++++++++++++---------------- + 1 file changed, 28 insertions(+), 22 deletions(-) + +diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp +index 4c265d5..1a3504f 100644 +--- a/hotspot/src/os/linux/vm/os_linux.cpp ++++ b/hotspot/src/os/linux/vm/os_linux.cpp +@@ -2302,29 +2302,35 @@ void os::Linux::print_process_memory_info(outputStream* st) { + int num_found = 0; + FILE* f = ::fopen("/proc/self/status", "r"); + char buf[256]; +- while (::fgets(buf, sizeof(buf), f) != NULL && num_found < num_values) { +- if ( (vmsize == -1 && sscanf(buf, "VmSize: " SSIZE_FORMAT " kB", &vmsize) == 1) || +- (vmpeak == -1 && sscanf(buf, "VmPeak: " SSIZE_FORMAT " kB", &vmpeak) == 1) || +- (vmswap == -1 && sscanf(buf, "VmSwap: " SSIZE_FORMAT " kB", &vmswap) == 1) || +- (vmhwm == -1 && sscanf(buf, "VmHWM: " SSIZE_FORMAT " kB", &vmhwm) == 1) || +- (vmrss == -1 && sscanf(buf, "VmRSS: " SSIZE_FORMAT " kB", &vmrss) == 1) || +- (rssanon == -1 && sscanf(buf, "RssAnon: " SSIZE_FORMAT " kB", &rssanon) == 1) || +- (rssfile == -1 && sscanf(buf, "RssFile: " SSIZE_FORMAT " kB", &rssfile) == 1) || +- (rssshmem == -1 && sscanf(buf, "RssShmem: " SSIZE_FORMAT " kB", &rssshmem) == 1) +- ) +- { +- num_found ++; ++ if (f != NULL) { ++ while (::fgets(buf, sizeof(buf), f) != NULL && num_found < num_values) { ++ if ( (vmsize == -1 && sscanf(buf, "VmSize: " SSIZE_FORMAT " kB", &vmsize) == 1) || ++ (vmpeak == -1 && sscanf(buf, "VmPeak: " SSIZE_FORMAT " kB", &vmpeak) == 1) || ++ (vmswap == -1 && sscanf(buf, "VmSwap: " SSIZE_FORMAT " kB", &vmswap) == 1) || ++ (vmhwm == -1 && sscanf(buf, "VmHWM: " SSIZE_FORMAT " kB", &vmhwm) == 1) || ++ (vmrss == -1 && sscanf(buf, "VmRSS: " SSIZE_FORMAT " kB", &vmrss) == 1) || ++ (rssanon == -1 && sscanf(buf, "RssAnon: " SSIZE_FORMAT " kB", &rssanon) == 1) || ++ (rssfile == -1 && sscanf(buf, "RssFile: " SSIZE_FORMAT " kB", &rssfile) == 1) || ++ (rssshmem == -1 && sscanf(buf, "RssShmem: " SSIZE_FORMAT " kB", &rssshmem) == 1) ++ ) ++ { ++ num_found ++; ++ } + } +- } +- st->print_cr("Virtual Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", vmsize, vmpeak); +- st->print("Resident Set Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", vmrss, vmhwm); +- if (rssanon != -1) { // requires kernel >= 4.5 +- st->print(" (anon: " SSIZE_FORMAT "K, file: " SSIZE_FORMAT "K, shmem: " SSIZE_FORMAT "K)", +- rssanon, rssfile, rssshmem); +- } +- st->cr(); +- if (vmswap != -1) { // requires kernel >= 2.6.34 +- st->print_cr("Swapped out: " SSIZE_FORMAT "K", vmswap); ++ fclose(f); ++ ++ st->print_cr("Virtual Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", vmsize, vmpeak); ++ st->print("Resident Set Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", vmrss, vmhwm); ++ if (rssanon != -1) { // requires kernel >= 4.5 ++ st->print(" (anon: " SSIZE_FORMAT "K, file: " SSIZE_FORMAT "K, shmem: " SSIZE_FORMAT "K)", ++ rssanon, rssfile, rssshmem); ++ } ++ st->cr(); ++ if (vmswap != -1) { // requires kernel >= 2.6.34 ++ st->print_cr("Swapped out: " SSIZE_FORMAT "K", vmswap); ++ } ++ } else { ++ st->print_cr("Could not open /proc/self/status to get process memory related information"); + } + + // Print glibc outstanding allocations. +-- +1.8.3.1 diff --git a/8263185-Mallinfo-deprecated-in-glibc-2.33.patch b/8263185-Mallinfo-deprecated-in-glibc-2.33.patch new file mode 100644 index 0000000..f80335f --- /dev/null +++ b/8263185-Mallinfo-deprecated-in-glibc-2.33.patch @@ -0,0 +1,121 @@ +From ccd4293dbec4b1048bf7eb342b8de8241a3667d4 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Mon, 12 Dec 2022 18:44:43 +0800 +Subject: [PATCH 13/33] I68TO2: 8263185: Mallinfo deprecated in glibc 2.33 +--- + hotspot/src/os/linux/vm/os_linux.cpp | 39 ++++++++++++++++++++++++++---------- + hotspot/src/os/linux/vm/os_linux.hpp | 34 +++++++++++++++++++++++++++++++ + 2 files changed, 62 insertions(+), 11 deletions(-) + +diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp +index c687b1c..099dafa 100644 +--- a/hotspot/src/os/linux/vm/os_linux.cpp ++++ b/hotspot/src/os/linux/vm/os_linux.cpp +@@ -152,6 +152,11 @@ const char * os::Linux::_glibc_version = NULL; + const char * os::Linux::_libpthread_version = NULL; + pthread_condattr_t os::Linux::_condattr[1]; + ++#ifdef __GLIBC__ ++os::Linux::mallinfo_func_t os::Linux::_mallinfo = NULL; ++os::Linux::mallinfo2_func_t os::Linux::_mallinfo2 = NULL; ++#endif // __GLIBC__ ++ + static jlong initial_time_count=0; + + static int clock_tics_per_sec = 100; +@@ -2343,18 +2348,25 @@ void os::Linux::print_process_memory_info(outputStream* st) { + // Print glibc outstanding allocations. + // (note: there is no implementation of mallinfo for muslc) + #ifdef __GLIBC__ +- struct mallinfo mi = ::mallinfo(); +- +- // mallinfo is an old API. Member names mean next to nothing and, beyond that, are int. +- // So values may have wrapped around. Still useful enough to see how much glibc thinks +- // we allocated. +- const size_t total_allocated = (size_t)(unsigned)mi.uordblks; +- st->print("C-Heap outstanding allocations: " SIZE_FORMAT "K", total_allocated / K); +- // Since mallinfo members are int, glibc values may have wrapped. Warn about this. +- if ((info.vmrss * K) > UINT_MAX && (info.vmrss * K) > (total_allocated + UINT_MAX)) { +- st->print(" (may have wrapped)"); ++ size_t total_allocated = 0; ++ bool might_have_wrapped = false; ++ if (_mallinfo2 != NULL) { ++ struct glibc_mallinfo2 mi = _mallinfo2(); ++ total_allocated = mi.uordblks; ++ } else if (_mallinfo != NULL) { ++ // mallinfo is an old API. Member names mean next to nothing and, beyond that, are int. ++ // So values may have wrapped around. Still useful enough to see how much glibc thinks ++ // we allocated. ++ struct glibc_mallinfo mi = _mallinfo(); ++ total_allocated = (size_t)(unsigned)mi.uordblks; ++ // Since mallinfo members are int, glibc values may have wrapped. Warn about this. ++ might_have_wrapped = (info.vmrss * K) > UINT_MAX && (info.vmrss * K) > (total_allocated + UINT_MAX); ++ } ++ if (_mallinfo2 != NULL || _mallinfo != NULL) { ++ st->print_cr("C-Heap outstanding allocations: " SIZE_FORMAT "K%s", ++ total_allocated / K, ++ might_have_wrapped ? " (may have wrapped)" : ""); + } +- st->cr(); + + #endif // __GLIBC__ + +@@ -5174,6 +5186,11 @@ void os::init(void) { + + Linux::initialize_system_info(); + ++#ifdef __GLIBC__ ++ Linux::_mallinfo = CAST_TO_FN_PTR(Linux::mallinfo_func_t, dlsym(RTLD_DEFAULT, "mallinfo")); ++ Linux::_mallinfo2 = CAST_TO_FN_PTR(Linux::mallinfo2_func_t, dlsym(RTLD_DEFAULT, "mallinfo2")); ++#endif // __GLIBC__ ++ + // _main_thread points to the thread that created/loaded the JVM. + Linux::_main_thread = pthread_self(); + +diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp +index 2c4efff..2bb3fd2 100644 +--- a/hotspot/src/os/linux/vm/os_linux.hpp ++++ b/hotspot/src/os/linux/vm/os_linux.hpp +@@ -338,6 +338,40 @@ private: + }; + static NumaAllocationPolicy _current_numa_policy; + ++#ifdef __GLIBC__ ++ struct glibc_mallinfo { ++ int arena; ++ int ordblks; ++ int smblks; ++ int hblks; ++ int hblkhd; ++ int usmblks; ++ int fsmblks; ++ int uordblks; ++ int fordblks; ++ int keepcost; ++ }; ++ ++ struct glibc_mallinfo2 { ++ size_t arena; ++ size_t ordblks; ++ size_t smblks; ++ size_t hblks; ++ size_t hblkhd; ++ size_t usmblks; ++ size_t fsmblks; ++ size_t uordblks; ++ size_t fordblks; ++ size_t keepcost; ++ }; ++ ++ typedef struct glibc_mallinfo (*mallinfo_func_t)(void); ++ typedef struct glibc_mallinfo2 (*mallinfo2_func_t)(void); ++ ++ static mallinfo_func_t _mallinfo; ++ static mallinfo2_func_t _mallinfo2; ++#endif ++ + public: + static int sched_getcpu() { return _sched_getcpu != NULL ? _sched_getcpu() : -1; } + static int numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) { +-- +1.8.3.1 diff --git a/8268893-jcmd-to-trim-the-glibc-heap.patch b/8268893-jcmd-to-trim-the-glibc-heap.patch new file mode 100644 index 0000000..8c9f14b --- /dev/null +++ b/8268893-jcmd-to-trim-the-glibc-heap.patch @@ -0,0 +1,678 @@ +From 1b97a08d822b7e2388ded07c696fffe70b39697a Mon Sep 17 00:00:00 2001 +From: eapen +Date: Mon, 12 Dec 2022 17:40:09 +0800 +Subject: [PATCH 12/33] I68TO2: 8268893: jcmd to trim the glibc heap +--- + hotspot/src/os/linux/vm/os_linux.cpp | 57 ++++--- + hotspot/src/os/linux/vm/os_linux.hpp | 17 ++ + hotspot/src/os/linux/vm/trimCHeapDCmd.cpp | 77 +++++++++ + hotspot/src/os/linux/vm/trimCHeapDCmd.hpp | 52 ++++++ + .../src/share/vm/services/diagnosticCommand.cpp | 7 + + .../test/serviceability/dcmd/TrimLibcHeapTest.java | 53 ++++++ + .../oracle/java/testlibrary/CommandExecutor.java | 73 ++++++++ + .../java/testlibrary/CommandExecutorException.java | 36 ++++ + .../com/oracle/java/testlibrary/JMXExecutor.java | 185 +++++++++++++++++++++ + 9 files changed, 532 insertions(+), 25 deletions(-) + create mode 100644 hotspot/src/os/linux/vm/trimCHeapDCmd.cpp + create mode 100644 hotspot/src/os/linux/vm/trimCHeapDCmd.hpp + create mode 100644 hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java + create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/CommandExecutor.java + create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/CommandExecutorException.java + create mode 100644 hotspot/test/testlibrary/com/oracle/java/testlibrary/JMXExecutor.java + +diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp +index 1a3504f..c687b1c 100644 +--- a/hotspot/src/os/linux/vm/os_linux.cpp ++++ b/hotspot/src/os/linux/vm/os_linux.cpp +@@ -2290,44 +2290,51 @@ void os::Linux::print_system_memory_info(outputStream* st) { + st->cr(); + } + +-void os::Linux::print_process_memory_info(outputStream* st) { +- +- st->print_cr("Process Memory:"); +- +- // Print virtual and resident set size; peak values; swap; and for +- // rss its components if the kernel is recent enough. +- ssize_t vmsize = -1, vmpeak = -1, vmswap = -1, +- vmrss = -1, vmhwm = -1, rssanon = -1, rssfile = -1, rssshmem = -1; +- const int num_values = 8; +- int num_found = 0; ++bool os::Linux::query_process_memory_info(os::Linux::meminfo_t* info) { + FILE* f = ::fopen("/proc/self/status", "r"); ++ const int num_values = sizeof(os::Linux::meminfo_t) / sizeof(size_t); ++ int num_found = 0; + char buf[256]; ++ info->vmsize = info->vmpeak = info->vmrss = info->vmhwm = info->vmswap = ++ info->rssanon = info->rssfile = info->rssshmem = -1; + if (f != NULL) { + while (::fgets(buf, sizeof(buf), f) != NULL && num_found < num_values) { +- if ( (vmsize == -1 && sscanf(buf, "VmSize: " SSIZE_FORMAT " kB", &vmsize) == 1) || +- (vmpeak == -1 && sscanf(buf, "VmPeak: " SSIZE_FORMAT " kB", &vmpeak) == 1) || +- (vmswap == -1 && sscanf(buf, "VmSwap: " SSIZE_FORMAT " kB", &vmswap) == 1) || +- (vmhwm == -1 && sscanf(buf, "VmHWM: " SSIZE_FORMAT " kB", &vmhwm) == 1) || +- (vmrss == -1 && sscanf(buf, "VmRSS: " SSIZE_FORMAT " kB", &vmrss) == 1) || +- (rssanon == -1 && sscanf(buf, "RssAnon: " SSIZE_FORMAT " kB", &rssanon) == 1) || +- (rssfile == -1 && sscanf(buf, "RssFile: " SSIZE_FORMAT " kB", &rssfile) == 1) || +- (rssshmem == -1 && sscanf(buf, "RssShmem: " SSIZE_FORMAT " kB", &rssshmem) == 1) ++ if ( (info->vmsize == -1 && sscanf(buf, "VmSize: " SSIZE_FORMAT " kB", &info->vmsize) == 1) || ++ (info->vmpeak == -1 && sscanf(buf, "VmPeak: " SSIZE_FORMAT " kB", &info->vmpeak) == 1) || ++ (info->vmswap == -1 && sscanf(buf, "VmSwap: " SSIZE_FORMAT " kB", &info->vmswap) == 1) || ++ (info->vmhwm == -1 && sscanf(buf, "VmHWM: " SSIZE_FORMAT " kB", &info->vmhwm) == 1) || ++ (info->vmrss == -1 && sscanf(buf, "VmRSS: " SSIZE_FORMAT " kB", &info->vmrss) == 1) || ++ (info->rssanon == -1 && sscanf(buf, "RssAnon: " SSIZE_FORMAT " kB", &info->rssanon) == 1) || // Needs Linux 4.5 ++ (info->rssfile == -1 && sscanf(buf, "RssFile: " SSIZE_FORMAT " kB", &info->rssfile) == 1) || // Needs Linux 4.5 ++ (info->rssshmem == -1 && sscanf(buf, "RssShmem: " SSIZE_FORMAT " kB", &info->rssshmem) == 1) // Needs Linux 4.5 + ) + { + num_found ++; + } + } + fclose(f); ++ return true; ++ } ++ return false; ++} ++ ++void os::Linux::print_process_memory_info(outputStream* st) { + +- st->print_cr("Virtual Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", vmsize, vmpeak); +- st->print("Resident Set Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", vmrss, vmhwm); +- if (rssanon != -1) { // requires kernel >= 4.5 ++ st->print_cr("Process Memory:"); ++ ++ // Print virtual and resident set size; peak values; swap; and for ++ // rss its components if the kernel is recent enough. ++ meminfo_t info; ++ if (query_process_memory_info(&info)) { ++ st->print_cr("Virtual Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", info.vmsize, info.vmpeak); ++ st->print("Resident Set Size: " SSIZE_FORMAT "K (peak: " SSIZE_FORMAT "K)", info.vmrss, info.vmhwm); ++ if (info.rssanon != -1) { // requires kernel >= 4.5 + st->print(" (anon: " SSIZE_FORMAT "K, file: " SSIZE_FORMAT "K, shmem: " SSIZE_FORMAT "K)", +- rssanon, rssfile, rssshmem); ++ info.rssanon, info.rssfile, info.rssshmem); + } + st->cr(); +- if (vmswap != -1) { // requires kernel >= 2.6.34 +- st->print_cr("Swapped out: " SSIZE_FORMAT "K", vmswap); ++ if (info.vmswap != -1) { // requires kernel >= 2.6.34 ++ st->print_cr("Swapped out: " SSIZE_FORMAT "K", info.vmswap); + } + } else { + st->print_cr("Could not open /proc/self/status to get process memory related information"); +@@ -2344,7 +2351,7 @@ void os::Linux::print_process_memory_info(outputStream* st) { + const size_t total_allocated = (size_t)(unsigned)mi.uordblks; + st->print("C-Heap outstanding allocations: " SIZE_FORMAT "K", total_allocated / K); + // Since mallinfo members are int, glibc values may have wrapped. Warn about this. +- if ((vmrss * K) > UINT_MAX && (vmrss * K) > (total_allocated + UINT_MAX)) { ++ if ((info.vmrss * K) > UINT_MAX && (info.vmrss * K) > (total_allocated + UINT_MAX)) { + st->print(" (may have wrapped)"); + } + st->cr(); +diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp +index 066b03a..2c4efff 100644 +--- a/hotspot/src/os/linux/vm/os_linux.hpp ++++ b/hotspot/src/os/linux/vm/os_linux.hpp +@@ -243,6 +243,23 @@ class Linux { + public: + static pthread_condattr_t* condAttr() { return _condattr; } + ++ // Output structure for query_process_memory_info() ++ struct meminfo_t { ++ ssize_t vmsize; // current virtual size ++ ssize_t vmpeak; // peak virtual size ++ ssize_t vmrss; // current resident set size ++ ssize_t vmhwm; // peak resident set size ++ ssize_t vmswap; // swapped out ++ ssize_t rssanon; // resident set size (anonymous mappings, needs 4.5) ++ ssize_t rssfile; // resident set size (file mappings, needs 4.5) ++ ssize_t rssshmem; // resident set size (shared mappings, needs 4.5) ++ }; ++ ++ // Attempts to query memory information about the current process and return it in the output structure. ++ // May fail (returns false) or succeed (returns true) but not all output fields are available; unavailable ++ // fields will contain -1. ++ static bool query_process_memory_info(meminfo_t* info); ++ + // Stack repair handling + + // none present +diff --git a/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp b/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp +new file mode 100644 +index 0000000..95d03d9 +--- /dev/null ++++ b/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp +@@ -0,0 +1,77 @@ ++/* ++ * Copyright (c) 2021 SAP SE. All rights reserved. ++ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "runtime/os.hpp" ++#include "utilities/debug.hpp" ++#include "utilities/ostream.hpp" ++#include "trimCHeapDCmd.hpp" ++ ++#include ++ ++void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) { ++#ifdef __GLIBC__ ++ stringStream ss_report(1024); // Note: before calling trim ++ ++ os::Linux::meminfo_t info1; ++ os::Linux::meminfo_t info2; ++ // Query memory before... ++ bool have_info1 = os::Linux::query_process_memory_info(&info1); ++ ++ _output->print_cr("Attempting trim..."); ++ ::malloc_trim(0); ++ _output->print_cr("Done."); ++ ++ // ...and after trim. ++ bool have_info2 = os::Linux::query_process_memory_info(&info2); ++ ++ // Print report both to output stream as well to UL ++ bool wrote_something = false; ++ if (have_info1 && have_info2) { ++ if (info1.vmsize != -1 && info2.vmsize != -1) { ++ ss_report.print_cr("Virtual size before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)", ++ info1.vmsize, info2.vmsize, (info2.vmsize - info1.vmsize)); ++ wrote_something = true; ++ } ++ if (info1.vmrss != -1 && info2.vmrss != -1) { ++ ss_report.print_cr("RSS before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)", ++ info1.vmrss, info2.vmrss, (info2.vmrss - info1.vmrss)); ++ wrote_something = true; ++ } ++ if (info1.vmswap != -1 && info2.vmswap != -1) { ++ ss_report.print_cr("Swap before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)", ++ info1.vmswap, info2.vmswap, (info2.vmswap - info1.vmswap)); ++ wrote_something = true; ++ } ++ } ++ if (!wrote_something) { ++ ss_report.print_raw("No details available."); ++ } ++ ++ _output->print_raw(ss_report.base()); ++#else ++ _output->print_cr("Not available."); ++#endif ++} +diff --git a/hotspot/src/os/linux/vm/trimCHeapDCmd.hpp b/hotspot/src/os/linux/vm/trimCHeapDCmd.hpp +new file mode 100644 +index 0000000..4c5b5cc +--- /dev/null ++++ b/hotspot/src/os/linux/vm/trimCHeapDCmd.hpp +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (c) 2021 SAP SE. All rights reserved. ++ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#ifndef OS_LINUX_TRIMCHEAPDCMD_HPP ++#define OS_LINUX_TRIMCHEAPDCMD_HPP ++ ++#include "services/diagnosticCommand.hpp" ++ ++class outputStream; ++ ++class TrimCLibcHeapDCmd : public DCmd { ++public: ++ TrimCLibcHeapDCmd(outputStream* output, bool heap) : DCmd(output, heap) {} ++ static const char* name() { ++ return "System.trim_native_heap"; ++ } ++ static const char* description() { ++ return "Attempts to free up memory by trimming the C-heap."; ++ } ++ static const char* impact() { ++ return "Low"; ++ } ++ static const JavaPermission permission() { ++ JavaPermission p = { "java.lang.management.ManagementPermission", "control", NULL }; ++ return p; ++ } ++ virtual void execute(DCmdSource source, TRAPS); ++}; ++ ++#endif // OS_LINUX_TRIMCHEAPDCMD_HPP +diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp +index 358ec6e..60417b5 100644 +--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp ++++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp +@@ -36,6 +36,10 @@ + #include "utilities/macros.hpp" + #include "oops/objArrayOop.hpp" + ++#ifdef LINUX ++#include "trimCHeapDCmd.hpp" ++#endif ++ + PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC + + void DCmdRegistrant::register_dcmds(){ +@@ -65,6 +69,9 @@ void DCmdRegistrant::register_dcmds(){ + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); ++#ifdef LINUX ++ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); ++#endif // LINUX + + // Enhanced JMX Agent Support + // These commands won't be exported via the DiagnosticCommandMBean until an +diff --git a/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java b/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java +new file mode 100644 +index 0000000..0fe8e35 +--- /dev/null ++++ b/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java +@@ -0,0 +1,53 @@ ++/* ++ * Copyright (c) 2021 SAP SE. All rights reserved. ++ * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. ++ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ */ ++ ++import org.testng.annotations.Test; ++import com.oracle.java.testlibrary.*; ++ ++/* ++ * @test ++ * @summary Test of diagnostic command VM.trim_libc_heap ++ * @library /testlibrary ++ * @requires os.family == "linux" ++ * @modules java.base/jdk.internal.misc ++ * java.compiler ++ * java.management ++ * jdk.internal.jvmstat/sun.jvmstat.monitor ++ * @run testng TrimLibcHeapTest ++ */ ++public class TrimLibcHeapTest { ++ public void run(CommandExecutor executor) { ++ OutputAnalyzer output = executor.execute("System.trim_native_heap"); ++ output.reportDiagnosticSummary(); ++ output.shouldMatch("(Done|Not available)"); // Not available could happen on Linux + non-glibc (eg. muslc) ++ if (output.firstMatch("Done") != null) { ++ output.shouldMatch("(Virtual size before|RSS before|Swap before|No details available)"); ++ } ++ } ++ ++ @Test ++ public void jmx() { ++ run(new JMXExecutor()); ++ } ++} +diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/CommandExecutor.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/CommandExecutor.java +new file mode 100644 +index 0000000..e95a437 +--- /dev/null ++++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/CommandExecutor.java +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. ++ * 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 com.oracle.java.testlibrary; ++ ++/** ++ * Abstract base class for Diagnostic Command executors ++ */ ++public abstract class CommandExecutor { ++ ++ /** ++ * Execute a diagnostic command ++ * ++ * @param cmd The diagnostic command to execute ++ * @return an {@link jdk.testlibrary.OutputAnalyzer} encapsulating the output of the command ++ * @throws CommandExecutorException if there is an exception on the "calling side" while trying to execute the ++ * Diagnostic Command. Exceptions thrown on the remote side are available as textual representations in ++ * stderr, regardless of the specific executor used. ++ */ ++ public final OutputAnalyzer execute(String cmd) throws CommandExecutorException { ++ return execute(cmd, false); ++ } ++ ++ /** ++ * Execute a diagnostic command ++ * ++ * @param cmd The diagnostic command to execute ++ * @param silent Do not print the command output ++ * @return an {@link jdk.testlibrary.OutputAnalyzer} encapsulating the output of the command ++ * @throws CommandExecutorException if there is an exception on the "calling side" while trying to execute the ++ * Diagnostic Command. Exceptions thrown on the remote side are available as textual representations in ++ * stderr, regardless of the specific executor used. ++ */ ++ public final OutputAnalyzer execute(String cmd, boolean silent) throws CommandExecutorException { ++ if (!silent) { ++ System.out.printf("Running DCMD '%s' through '%s'%n", cmd, this.getClass().getSimpleName()); ++ } ++ ++ OutputAnalyzer oa = executeImpl(cmd); ++ ++ if (!silent) { ++ System.out.println("---------------- stdout ----------------"); ++ System.out.println(oa.getStdout()); ++ System.out.println("---------------- stderr ----------------"); ++ System.out.println(oa.getStderr()); ++ System.out.println("----------------------------------------"); ++ System.out.println(); ++ } ++ return oa; ++ } ++ ++ protected abstract OutputAnalyzer executeImpl(String cmd) throws CommandExecutorException; ++} +diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/CommandExecutorException.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/CommandExecutorException.java +new file mode 100644 +index 0000000..1857a23 +--- /dev/null ++++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/CommandExecutorException.java +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. ++ * 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 com.oracle.java.testlibrary; ++ ++/** ++ * CommandExecutorException encapsulates exceptions thrown (on the "calling side") from the execution of Diagnostic ++ * Commands ++ */ ++public class CommandExecutorException extends RuntimeException { ++ private static final long serialVersionUID = -7039597746579144280L; ++ ++ public CommandExecutorException(String message, Throwable e) { ++ super(message, e); ++ } ++} +diff --git a/hotspot/test/testlibrary/com/oracle/java/testlibrary/JMXExecutor.java b/hotspot/test/testlibrary/com/oracle/java/testlibrary/JMXExecutor.java +new file mode 100644 +index 0000000..317fc5c +--- /dev/null ++++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/JMXExecutor.java +@@ -0,0 +1,185 @@ ++/* ++ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. ++ * 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 com.oracle.java.testlibrary; ++ ++import javax.management.*; ++import javax.management.remote.JMXConnector; ++import javax.management.remote.JMXConnectorFactory; ++import javax.management.remote.JMXServiceURL; ++ ++import java.io.IOException; ++import java.io.PrintWriter; ++import java.io.StringWriter; ++ ++import java.lang.management.ManagementFactory; ++ ++import java.util.HashMap; ++ ++/** ++ * Executes Diagnostic Commands on the target VM (specified by a host/port combination or a full JMX Service URL) using ++ * the JMX interface. If the target is not the current VM, the JMX Remote interface must be enabled beforehand. ++ */ ++public class JMXExecutor extends CommandExecutor { ++ ++ private final MBeanServerConnection mbs; ++ ++ /** ++ * Instantiates a new JMXExecutor targeting the current VM ++ */ ++ public JMXExecutor() { ++ super(); ++ mbs = ManagementFactory.getPlatformMBeanServer(); ++ } ++ ++ /** ++ * Instantiates a new JMXExecutor targeting the VM indicated by the given host/port combination or a full JMX ++ * Service URL ++ * ++ * @param target a host/port combination on the format "host:port" or a full JMX Service URL of the target VM ++ */ ++ public JMXExecutor(String target) { ++ String urlStr; ++ ++ if (target.matches("^\\w[\\w\\-]*(\\.[\\w\\-]+)*:\\d+$")) { ++ /* Matches "hostname:port" */ ++ urlStr = String.format("service:jmx:rmi:///jndi/rmi://%s/jmxrmi", target); ++ } else if (target.startsWith("service:")) { ++ urlStr = target; ++ } else { ++ throw new IllegalArgumentException("Could not recognize target string: " + target); ++ } ++ ++ try { ++ JMXServiceURL url = new JMXServiceURL(urlStr); ++ JMXConnector c = JMXConnectorFactory.connect(url, new HashMap<>()); ++ mbs = c.getMBeanServerConnection(); ++ } catch (IOException e) { ++ throw new CommandExecutorException("Could not initiate connection to target: " + target, e); ++ } ++ } ++ ++ protected OutputAnalyzer executeImpl(String cmd) throws CommandExecutorException { ++ String stdout = ""; ++ String stderr = ""; ++ ++ String[] cmdParts = cmd.split(" ", 2); ++ String operation = commandToMethodName(cmdParts[0]); ++ Object[] dcmdArgs = produceArguments(cmdParts); ++ String[] signature = {String[].class.getName()}; ++ ++ ObjectName beanName = getMBeanName(); ++ ++ try { ++ stdout = (String) mbs.invoke(beanName, operation, dcmdArgs, signature); ++ } ++ ++ /* Failures on the "local" side, the one invoking the command. */ ++ catch (ReflectionException e) { ++ Throwable cause = e.getCause(); ++ if (cause instanceof NoSuchMethodException) { ++ /* We want JMXExecutor to match the behavior of the other CommandExecutors */ ++ String message = "Unknown diagnostic command: " + operation; ++ stderr = exceptionTraceAsString(new IllegalArgumentException(message, e)); ++ } else { ++ rethrowExecutorException(operation, dcmdArgs, e); ++ } ++ } ++ ++ /* Failures on the "local" side, the one invoking the command. */ ++ catch (InstanceNotFoundException | IOException e) { ++ rethrowExecutorException(operation, dcmdArgs, e); ++ } ++ ++ /* Failures on the remote side, the one executing the invoked command. */ ++ catch (MBeanException e) { ++ stdout = exceptionTraceAsString(e); ++ } ++ ++ return new OutputAnalyzer(stdout, stderr); ++ } ++ ++ private void rethrowExecutorException(String operation, Object[] dcmdArgs, ++ Exception e) throws CommandExecutorException { ++ String message = String.format("Could not invoke: %s %s", operation, ++ String.join(" ", (String[]) dcmdArgs[0])); ++ throw new CommandExecutorException(message, e); ++ } ++ ++ private ObjectName getMBeanName() throws CommandExecutorException { ++ String MBeanName = "com.sun.management:type=DiagnosticCommand"; ++ ++ try { ++ return new ObjectName(MBeanName); ++ } catch (MalformedObjectNameException e) { ++ String message = "MBean not found: " + MBeanName; ++ throw new CommandExecutorException(message, e); ++ } ++ } ++ ++ private Object[] produceArguments(String[] cmdParts) { ++ Object[] dcmdArgs = {new String[0]}; /* Default: No arguments */ ++ ++ if (cmdParts.length == 2) { ++ dcmdArgs[0] = cmdParts[1].split(" "); ++ } ++ return dcmdArgs; ++ } ++ ++ /** ++ * Convert from diagnostic command to MBean method name ++ * ++ * Examples: ++ * help --> help ++ * VM.version --> vmVersion ++ * VM.command_line --> vmCommandLine ++ */ ++ private static String commandToMethodName(String cmd) { ++ String operation = ""; ++ boolean up = false; /* First letter is to be lower case */ ++ ++ /* ++ * If a '.' or '_' is encountered it is not copied, ++ * instead the next character will be converted to upper case ++ */ ++ for (char c : cmd.toCharArray()) { ++ if (('.' == c) || ('_' == c)) { ++ up = true; ++ } else if (up) { ++ operation = operation.concat(Character.toString(c).toUpperCase()); ++ up = false; ++ } else { ++ operation = operation.concat(Character.toString(c).toLowerCase()); ++ } ++ } ++ ++ return operation; ++ } ++ ++ private static String exceptionTraceAsString(Throwable cause) { ++ StringWriter sw = new StringWriter(); ++ cause.printStackTrace(new PrintWriter(sw)); ++ return sw.toString(); ++ } ++ ++} +-- +1.8.3.1 diff --git a/8275775-Add-jcmd-VM.classes-to-print-details-of-all-.patch b/8275775-Add-jcmd-VM.classes-to-print-details-of-all-.patch new file mode 100644 index 0000000..3d089b3 --- /dev/null +++ b/8275775-Add-jcmd-VM.classes-to-print-details-of-all-.patch @@ -0,0 +1,430 @@ +From c427ef7ceeea1fb8f8ebd035e59b6f06b5ec34c1 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Tue, 13 Dec 2022 21:06:41 +0800 +Subject: [PATCH 15/33] I68TO2: 8275775: Add jcmd VM.classes to print details of all + classes +--- + hotspot/src/share/vm/oops/instanceKlass.cpp | 56 ++++++++++++++++++++-- + hotspot/src/share/vm/oops/instanceKlass.hpp | 17 ++++--- + hotspot/src/share/vm/runtime/fieldDescriptor.cpp | 4 +- + hotspot/src/share/vm/runtime/fieldDescriptor.hpp | 4 +- + hotspot/src/share/vm/runtime/globals.hpp | 2 +- + hotspot/src/share/vm/runtime/vm_operations.hpp | 1 + + .../src/share/vm/services/diagnosticCommand.cpp | 53 ++++++++++++++++++++ + .../src/share/vm/services/diagnosticCommand.hpp | 23 +++++++++ + hotspot/test/runtime/CommandLine/PrintClasses.java | 51 ++++++++++++++++++++ + 9 files changed, 195 insertions(+), 16 deletions(-) + create mode 100644 hotspot/test/runtime/CommandLine/PrintClasses.java + +diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp +index 2a9cd92..538645b 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.cpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.cpp +@@ -1799,6 +1799,52 @@ Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name, + return NULL; + } + ++PrintClassClosure::PrintClassClosure(outputStream* st, bool verbose) ++ :_st(st), _verbose(verbose) { ++ ResourceMark rm; ++ _st->print("%-18s ", "KlassAddr"); ++ _st->print("%-4s ", "Size"); ++ _st->print("%-20s ", "State"); ++ _st->print("%-7s ", "Flags"); ++ _st->print("%-5s ", "ClassName"); ++ _st->cr(); ++} ++ ++void PrintClassClosure::do_klass(Klass* k) { ++ ResourceMark rm; ++ // klass pointer ++ _st->print(INTPTR_FORMAT " ", p2i(k)); ++ // klass size ++ _st->print("%4d ", k->size()); ++ // initialization state ++ if (k->oop_is_instance()) { ++ _st->print("%-20s ",InstanceKlass::cast(k)->init_state_name()); ++ } else { ++ _st->print("%-20s ",""); ++ } ++ // misc flags(Changes should synced with ClassesDCmd::ClassesDCmd help doc) ++ char buf[10]; ++ int i = 0; ++ if (k->has_finalizer()) buf[i++] = 'F'; ++ if (k->has_final_method()) buf[i++] = 'f'; ++ if (k->oop_is_instance()) { ++ InstanceKlass* ik = InstanceKlass::cast(k); ++ if (ik->is_rewritten()) buf[i++] = 'W'; ++ if (ik->is_contended()) buf[i++] = 'C'; ++ if (ik->has_been_redefined()) buf[i++] = 'R'; ++ if (ik->is_shared()) buf[i++] = 'S'; ++ } ++ buf[i++] = '\0'; ++ _st->print("%-7s ", buf); ++ // klass name ++ _st->print("%-5s ", k->external_name()); ++ // end ++ _st->cr(); ++ if (_verbose) { ++ k->print_on(_st); ++ } ++} ++ + /* jni_id_for_impl for jfieldIds only */ + JNIid* InstanceKlass::jni_id_for_impl(instanceKlassHandle this_oop, int offset) { + MutexLocker ml(JfieldIdCreation_lock); +@@ -3244,7 +3290,6 @@ oop InstanceKlass::add_member_name(Handle mem_name, bool intern) { + // ----------------------------------------------------------------------------------------------------- + // Printing + +-#ifndef PRODUCT + + #define BULLET " - " + +@@ -3264,6 +3309,10 @@ static void print_vtable(intptr_t* start, int len, outputStream* st) { + } + } + ++const char* InstanceKlass::init_state_name() const { ++ return state_names[_init_state]; ++} ++ + void InstanceKlass::print_on(outputStream* st) const { + assert(is_klass(), "must be klass"); + Klass::print_on(st); +@@ -3271,7 +3320,7 @@ void InstanceKlass::print_on(outputStream* st) const { + st->print(BULLET"instance size: %d", size_helper()); st->cr(); + st->print(BULLET"klass size: %d", size()); st->cr(); + st->print(BULLET"access: "); access_flags().print_on(st); st->cr(); +- st->print(BULLET"state: "); st->print_cr("%s", state_names[_init_state]); ++ st->print(BULLET"state: "); st->print_cr("%s", init_state_name()); + st->print(BULLET"name: "); name()->print_value_on(st); st->cr(); + st->print(BULLET"super: "); super()->print_value_on_maybe_null(st); st->cr(); + st->print(BULLET"sub: "); +@@ -3380,7 +3429,6 @@ void InstanceKlass::print_on(outputStream* st) const { + st->cr(); + } + +-#endif //PRODUCT + + void InstanceKlass::print_value_on(outputStream* st) const { + assert(is_klass(), "must be klass"); +@@ -3388,7 +3436,6 @@ void InstanceKlass::print_value_on(outputStream* st) const { + name()->print_value_on(st); + } + +-#ifndef PRODUCT + + void FieldPrinter::do_field(fieldDescriptor* fd) { + _st->print(BULLET); +@@ -3449,7 +3496,6 @@ void InstanceKlass::oop_print_on(oop obj, outputStream* st) { + } + } + +-#endif //PRODUCT + + void InstanceKlass::oop_print_value_on(oop obj, outputStream* st) { + st->print("a "); +diff --git a/hotspot/src/share/vm/oops/instanceKlass.hpp b/hotspot/src/share/vm/oops/instanceKlass.hpp +index 43919e8..6e36fa4 100644 +--- a/hotspot/src/share/vm/oops/instanceKlass.hpp ++++ b/hotspot/src/share/vm/oops/instanceKlass.hpp +@@ -99,7 +99,6 @@ public: + virtual void do_field(fieldDescriptor* fd) = 0; + }; + +-#ifndef PRODUCT + // Print fields. + // If "obj" argument to constructor is NULL, prints static fields, otherwise prints non-static fields. + class FieldPrinter: public FieldClosure { +@@ -109,7 +108,6 @@ class FieldPrinter: public FieldClosure { + FieldPrinter(outputStream* st, oop obj = NULL) : _obj(obj), _st(st) {} + void do_field(fieldDescriptor* fd); + }; +-#endif // !PRODUCT + + // ValueObjs embedded in klass. Describes where oops are located in instances of + // this klass. +@@ -462,6 +460,7 @@ class InstanceKlass: public Klass { + bool is_in_error_state() const { return _init_state == initialization_error; } + bool is_reentrant_initialization(Thread *thread) { return thread == _init_thread; } + ClassState init_state() { return (ClassState)_init_state; } ++ const char* init_state_name() const; + bool is_rewritten() const { return (_misc_flags & _misc_rewritten) != 0; } + + // defineClass specified verification +@@ -1174,16 +1173,13 @@ public: + + public: + // Printing +-#ifndef PRODUCT + void print_on(outputStream* st) const; +-#endif + void print_value_on(outputStream* st) const; + + void oop_print_value_on(oop obj, outputStream* st); + +-#ifndef PRODUCT + void oop_print_on (oop obj, outputStream* st); +- ++#ifndef PRODUCT + void print_dependent_nmethods(bool verbose = false); + bool is_dependent_nmethod(nmethod* nm); + #endif +@@ -1217,6 +1213,15 @@ inline u2 InstanceKlass::next_method_idnum() { + } + } + ++class PrintClassClosure : public KlassClosure { ++private: ++ outputStream* _st; ++ bool _verbose; ++public: ++ PrintClassClosure(outputStream* st, bool verbose); ++ ++ void do_klass(Klass* k); ++}; + + /* JNIid class for jfieldIDs only */ + class JNIid: public CHeapObj { +diff --git a/hotspot/src/share/vm/runtime/fieldDescriptor.cpp b/hotspot/src/share/vm/runtime/fieldDescriptor.cpp +index 610402d..288e82d 100644 +--- a/hotspot/src/share/vm/runtime/fieldDescriptor.cpp ++++ b/hotspot/src/share/vm/runtime/fieldDescriptor.cpp +@@ -123,6 +123,8 @@ void fieldDescriptor::verify() const { + } + } + ++#endif /* PRODUCT */ ++ + void fieldDescriptor::print_on(outputStream* st) const { + access_flags().print_on(st); + name()->print_value_on(st); +@@ -206,5 +208,3 @@ void fieldDescriptor::print_on_for(outputStream* st, oop obj) { + st->print(" (%x)", as_int); + } + } +- +-#endif /* PRODUCT */ +diff --git a/hotspot/src/share/vm/runtime/fieldDescriptor.hpp b/hotspot/src/share/vm/runtime/fieldDescriptor.hpp +index 1810a16..f7e9a26 100644 +--- a/hotspot/src/share/vm/runtime/fieldDescriptor.hpp ++++ b/hotspot/src/share/vm/runtime/fieldDescriptor.hpp +@@ -129,8 +129,8 @@ class fieldDescriptor VALUE_OBJ_CLASS_SPEC { + + // Print + void print() { print_on(tty); } +- void print_on(outputStream* st) const PRODUCT_RETURN; +- void print_on_for(outputStream* st, oop obj) PRODUCT_RETURN; ++ void print_on(outputStream* st) const; ++ void print_on_for(outputStream* st, oop obj); + void verify() const PRODUCT_RETURN; + }; + +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index ec48c48..41b1392 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -3097,7 +3097,7 @@ class CommandLineFlags { + notproduct(intx, MaxElementPrintSize, 256, \ + "maximum number of elements to print") \ + \ +- notproduct(intx, MaxSubklassPrintSize, 4, \ ++ product(intx, MaxSubklassPrintSize, 4, \ + "maximum number of subklasses to print when printing klass") \ + \ + product(intx, MaxInlineLevel, 9, \ +diff --git a/hotspot/src/share/vm/runtime/vm_operations.hpp b/hotspot/src/share/vm/runtime/vm_operations.hpp +index 8c6795a..a8ba78b 100644 +--- a/hotspot/src/share/vm/runtime/vm_operations.hpp ++++ b/hotspot/src/share/vm/runtime/vm_operations.hpp +@@ -99,6 +99,7 @@ + template(WhiteBoxOperation) \ + template(ClassLoaderStatsOperation) \ + template(JFROldObject) \ ++ template(PrintClasses) \ + + class VM_Operation: public CHeapObj { + public: +diff --git a/hotspot/src/share/vm/services/diagnosticCommand.cpp b/hotspot/src/share/vm/services/diagnosticCommand.cpp +index 60417b5..e4e6185 100644 +--- a/hotspot/src/share/vm/services/diagnosticCommand.cpp ++++ b/hotspot/src/share/vm/services/diagnosticCommand.cpp +@@ -64,6 +64,7 @@ void DCmdRegistrant::register_dcmds(){ + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); ++ DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); + #endif // INCLUDE_SERVICES + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl(full_export, true, false)); +@@ -98,9 +99,14 @@ HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, hea + _dcmdparser.add_dcmd_argument(&_cmd); + }; + ++static int compare_strings(const char** s1, const char** s2) { ++ return ::strcmp(*s1, *s2); ++} ++ + void HelpDCmd::execute(DCmdSource source, TRAPS) { + if (_all.value()) { + GrowableArray* cmd_list = DCmdFactory::DCmd_list(source); ++ cmd_list->sort(compare_strings); + for (int i = 0; i < cmd_list->length(); i++) { + DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i), + strlen(cmd_list->at(i))); +@@ -141,6 +147,7 @@ void HelpDCmd::execute(DCmdSource source, TRAPS) { + } else { + output()->print_cr("The following commands are available:"); + GrowableArray* cmd_list = DCmdFactory::DCmd_list(source); ++ cmd_list->sort(compare_strings); + for (int i = 0; i < cmd_list->length(); i++) { + DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i), + strlen(cmd_list->at(i))); +@@ -419,6 +426,52 @@ int ClassHistogramDCmd::num_arguments() { + } + } + ++ClassesDCmd::ClassesDCmd(outputStream* output, bool heap) : ++ DCmdWithParser(output, heap), ++ _verbose("-verbose", ++ "Dump the detailed content of a Java class. " ++ "Some classes are annotated with flags: " ++ "F = has, or inherits, a non-empty finalize method, " ++ "f = has final method, " ++ "W = methods rewritten, " ++ "C = marked with @Contended annotation, " ++ "R = has been redefined, " ++ "S = is shared class", ++ "BOOLEAN", false, "false") { ++ _dcmdparser.add_dcmd_option(&_verbose); ++} ++ ++class VM_PrintClasses : public VM_Operation { ++private: ++ outputStream* _out; ++ bool _verbose; ++public: ++ VM_PrintClasses(outputStream* out, bool verbose) : _out(out), _verbose(verbose) {} ++ ++ virtual VMOp_Type type() const { return VMOp_PrintClasses; } ++ ++ virtual void doit() { ++ PrintClassClosure closure(_out, _verbose); ++ ClassLoaderDataGraph::classes_do(&closure); ++ } ++}; ++ ++void ClassesDCmd::execute(DCmdSource source, TRAPS) { ++ VM_PrintClasses vmop(output(), _verbose.is_set()); ++ VMThread::execute(&vmop); ++} ++ ++int ClassesDCmd::num_arguments() { ++ ResourceMark rm; ++ ClassesDCmd* dcmd = new ClassesDCmd(NULL, false); ++ if (dcmd != NULL) { ++ DCmdMark mark(dcmd); ++ return dcmd->_dcmdparser.num_arguments(); ++ } else { ++ return 0; ++ } ++} ++ + #define DEFAULT_COLUMNS "InstBytes,KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total" + ClassStatsDCmd::ClassStatsDCmd(outputStream* output, bool heap) : + DCmdWithParser(output, heap), +diff --git a/hotspot/src/share/vm/services/diagnosticCommand.hpp b/hotspot/src/share/vm/services/diagnosticCommand.hpp +index e28011f..f86ab5f 100644 +--- a/hotspot/src/share/vm/services/diagnosticCommand.hpp ++++ b/hotspot/src/share/vm/services/diagnosticCommand.hpp +@@ -314,6 +314,29 @@ public: + virtual void execute(DCmdSource source, TRAPS); + }; + ++class ClassesDCmd : public DCmdWithParser { ++protected: ++ DCmdArgument _verbose; ++public: ++ ClassesDCmd(outputStream* output, bool heap); ++ static const char* name() { ++ return "VM.classes"; ++ } ++ static const char* description() { ++ return "Print all loaded classes"; ++ } ++ static const char* impact() { ++ return "Medium: Depends on number of loaded classes."; ++ } ++ static const JavaPermission permission() { ++ JavaPermission p = {"java.lang.management.ManagementPermission", ++ "monitor", NULL}; ++ return p; ++ } ++ static int num_arguments(); ++ virtual void execute(DCmdSource source, TRAPS); ++}; ++ + class ClassStatsDCmd : public DCmdWithParser { + protected: + DCmdArgument _all; +diff --git a/hotspot/test/runtime/CommandLine/PrintClasses.java b/hotspot/test/runtime/CommandLine/PrintClasses.java +new file mode 100644 +index 0000000..7c1d4db +--- /dev/null ++++ b/hotspot/test/runtime/CommandLine/PrintClasses.java +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (c) 2022, Alibaba Group Holding Limited. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * 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 8275775 ++ * @summary Test jcmd VM.classes ++ * @library /testlibrary ++ * @run main/othervm PrintClasses ++ */ ++ ++import com.oracle.java.testlibrary.*; ++ ++public class PrintClasses { ++ public static void main(String args[]) throws Exception { ++ String pid = Integer.toString(ProcessTools.getProcessId()); ++ ProcessBuilder pb = new ProcessBuilder(); ++ ++ pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.classes"}); ++ OutputAnalyzer output = new OutputAnalyzer(pb.start()); ++ output.shouldNotContain("instance size"); ++ output.shouldContain(PrintClasses.class.getSimpleName()); ++ ++ pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.classes", "-verbose"}); ++ output = new OutputAnalyzer(pb.start()); ++ output.shouldContain("instance size"); ++ output.shouldContain(PrintClasses.class.getSimpleName()); ++ } ++} +\ No newline at end of file +-- +1.8.3.1 diff --git a/8293114-GC-should-trim-the-native-heap-and-bug-fix.patch b/8293114-GC-should-trim-the-native-heap-and-bug-fix.patch new file mode 100644 index 0000000..1cc4fed --- /dev/null +++ b/8293114-GC-should-trim-the-native-heap-and-bug-fix.patch @@ -0,0 +1,1503 @@ +From a5edc79220300bce7952feaacf28a832306884d8 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Mon, 12 Dec 2022 19:28:28 +0800 +Subject: [PATCH 14/33] I68TO2: 8293114: GC should trim the native heap,8136854:G1 ConcurrentG1RefineThread::stop delays JVM shutdown for >150ms +--- + hotspot/src/os/aix/vm/os_aix.cpp | 5 + + hotspot/src/os/bsd/vm/os_bsd.cpp | 5 + + hotspot/src/os/linux/vm/os_linux.cpp | 149 ++++++- + hotspot/src/os/linux/vm/os_linux.hpp | 57 ++- + hotspot/src/os/linux/vm/trimCHeapDCmd.cpp | 59 +-- + hotspot/src/os/windows/vm/os_windows.cpp | 4 + + .../vm/gc_implementation/g1/g1CollectedHeap.cpp | 6 + + .../parallelScavenge/parallelScavengeHeap.cpp | 3 + + .../parallelScavenge/psParallelCompact.cpp | 6 + + .../shared/concurrentGCThread.cpp | 8 +- + .../shared/concurrentGCThread.hpp | 6 +- + .../gc_implementation/shared/gcTrimNativeHeap.cpp | 246 ++++++++++++ + .../gc_implementation/shared/gcTrimNativeHeap.hpp | 66 ++++ + hotspot/src/share/vm/memory/genCollectedHeap.cpp | 6 + + hotspot/src/share/vm/memory/sharedHeap.cpp | 6 + + hotspot/src/share/vm/runtime/globals.hpp | 10 + + hotspot/src/share/vm/runtime/init.cpp | 5 +- + hotspot/src/share/vm/runtime/java.cpp | 3 + + hotspot/src/share/vm/runtime/os.hpp | 11 + + .../src/share/vm/utilities/globalDefinitions.hpp | 3 + + hotspot/test/gc/TestTrimNative.java | 435 +++++++++++++++++++++ + .../test/serviceability/dcmd/TrimLibcHeapTest.java | 7 +- + 22 files changed, 994 insertions(+), 112 deletions(-) + create mode 100644 hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.cpp + create mode 100644 hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.hpp + create mode 100644 hotspot/test/gc/TestTrimNative.java + +diff --git a/hotspot/src/os/aix/vm/os_aix.cpp b/hotspot/src/os/aix/vm/os_aix.cpp +index b078bee..519b085 100644 +--- a/hotspot/src/os/aix/vm/os_aix.cpp ++++ b/hotspot/src/os/aix/vm/os_aix.cpp +@@ -5266,3 +5266,8 @@ void TestReserveMemorySpecial_test() { + // No tests available for this platform + } + #endif ++ ++// stubbed-out trim-native support ++bool os::can_trim_native_heap() { return false; } ++bool os::should_trim_native_heap() { return false; } ++bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } +\ No newline at end of file +diff --git a/hotspot/src/os/bsd/vm/os_bsd.cpp b/hotspot/src/os/bsd/vm/os_bsd.cpp +index 340334c..85e2861 100644 +--- a/hotspot/src/os/bsd/vm/os_bsd.cpp ++++ b/hotspot/src/os/bsd/vm/os_bsd.cpp +@@ -4899,3 +4899,8 @@ void TestReserveMemorySpecial_test() { + // No tests available for this platform + } + #endif ++ ++// stubbed-out trim-native support ++bool os::can_trim_native_heap() { return false; } ++bool os::should_trim_native_heap() { return false; } ++bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } +\ No newline at end of file +diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp +index 099dafa..abf2031 100644 +--- a/hotspot/src/os/linux/vm/os_linux.cpp ++++ b/hotspot/src/os/linux/vm/os_linux.cpp +@@ -153,8 +153,28 @@ const char * os::Linux::_libpthread_version = NULL; + pthread_condattr_t os::Linux::_condattr[1]; + + #ifdef __GLIBC__ +-os::Linux::mallinfo_func_t os::Linux::_mallinfo = NULL; +-os::Linux::mallinfo2_func_t os::Linux::_mallinfo2 = NULL; ++// We want to be runnable with both old and new glibcs. ++// Old glibcs offer mallinfo(). New glibcs deprecate mallinfo() and offer mallinfo2() ++// as replacement. Future glibc's may remove the deprecated mallinfo(). ++// Therefore we may have one, both, or possibly neither (?). Code should tolerate all ++// cases, which is why we resolve the functions dynamically. Outside code should use ++// the Linux::get_mallinfo() utility function which exists to hide this mess. ++struct glibc_mallinfo { ++ int arena; ++ int ordblks; ++ int smblks; ++ int hblks; ++ int hblkhd; ++ int usmblks; ++ int fsmblks; ++ int uordblks; ++ int fordblks; ++ int keepcost; ++}; ++typedef struct glibc_mallinfo (*mallinfo_func_t)(void); ++typedef struct os::Linux::glibc_mallinfo2 (*mallinfo2_func_t)(void); ++static mallinfo_func_t g_mallinfo = NULL; ++static mallinfo2_func_t g_mallinfo2 = NULL; + #endif // __GLIBC__ + + static jlong initial_time_count=0; +@@ -2348,23 +2368,21 @@ void os::Linux::print_process_memory_info(outputStream* st) { + // Print glibc outstanding allocations. + // (note: there is no implementation of mallinfo for muslc) + #ifdef __GLIBC__ +- size_t total_allocated = 0; + bool might_have_wrapped = false; +- if (_mallinfo2 != NULL) { +- struct glibc_mallinfo2 mi = _mallinfo2(); +- total_allocated = mi.uordblks; +- } else if (_mallinfo != NULL) { +- // mallinfo is an old API. Member names mean next to nothing and, beyond that, are int. +- // So values may have wrapped around. Still useful enough to see how much glibc thinks +- // we allocated. +- struct glibc_mallinfo mi = _mallinfo(); +- total_allocated = (size_t)(unsigned)mi.uordblks; +- // Since mallinfo members are int, glibc values may have wrapped. Warn about this. +- might_have_wrapped = (info.vmrss * K) > UINT_MAX && (info.vmrss * K) > (total_allocated + UINT_MAX); +- } +- if (_mallinfo2 != NULL || _mallinfo != NULL) { +- st->print_cr("C-Heap outstanding allocations: " SIZE_FORMAT "K%s", +- total_allocated / K, ++ glibc_mallinfo2 mi; ++ mallinfo_retval_t mirc = os::Linux::get_mallinfo(&mi); ++ if (mirc != os::Linux::error) { ++ size_t total_allocated = mi.uordblks + mi.hblkhd; ++ size_t free_retained = mi.fordblks; ++#ifdef _LP64 ++ // If all we had is old mallinf(3), the values may have wrapped. Since that can confuse readers ++ // of this output, print a hint. ++ // We do this by checking virtual size of the process: if that is <4g, we could not have wrapped. ++ might_have_wrapped = (mirc == os::Linux::ok_but_possibly_wrapped) && ++ ((info.vmsize * K) > UINT_MAX); ++#endif ++ st->print_cr("C-Heap outstanding allocations: " SIZE_FORMAT "K, retained: " SIZE_FORMAT "K%s", ++ total_allocated / K, free_retained / K, + might_have_wrapped ? " (may have wrapped)" : ""); + } + +@@ -5187,8 +5205,8 @@ void os::init(void) { + Linux::initialize_system_info(); + + #ifdef __GLIBC__ +- Linux::_mallinfo = CAST_TO_FN_PTR(Linux::mallinfo_func_t, dlsym(RTLD_DEFAULT, "mallinfo")); +- Linux::_mallinfo2 = CAST_TO_FN_PTR(Linux::mallinfo2_func_t, dlsym(RTLD_DEFAULT, "mallinfo2")); ++ g_mallinfo = CAST_TO_FN_PTR(mallinfo_func_t, dlsym(RTLD_DEFAULT, "mallinfo")); ++ g_mallinfo2 = CAST_TO_FN_PTR(mallinfo2_func_t, dlsym(RTLD_DEFAULT, "mallinfo2")); + #endif // __GLIBC__ + + // _main_thread points to the thread that created/loaded the JVM. +@@ -6820,3 +6838,94 @@ void TestReserveMemorySpecial_test() { + } + + #endif ++ ++#ifdef __GLIBC__ ++os::Linux::mallinfo_retval_t os::Linux::get_mallinfo(glibc_mallinfo2* out) { ++ if (g_mallinfo2) { ++ glibc_mallinfo2 mi = g_mallinfo2(); ++ *out = mi; ++ return os::Linux::ok; ++ } else if (g_mallinfo) { ++ // mallinfo() returns 32-bit values. Not perfect but still useful if ++ // process virt size < 4g ++ glibc_mallinfo mi = g_mallinfo(); ++ out->arena = (int) mi.arena; ++ out->ordblks = (int) mi.ordblks; ++ out->smblks = (int) mi.smblks; ++ out->hblks = (int) mi.hblks; ++ out->hblkhd = (int) mi.hblkhd; ++ out->usmblks = (int) mi.usmblks; ++ out->fsmblks = (int) mi.fsmblks; ++ out->uordblks = (int) mi.uordblks; ++ out->fordblks = (int) mi.fordblks; ++ out->keepcost = (int) mi.keepcost; ++ return os::Linux::ok_but_possibly_wrapped; ++ } ++ return os::Linux::ok; ++} ++#endif // __GLIBC__ ++ ++// Trim-native support ++bool os::can_trim_native_heap() { ++#ifdef __GLIBC__ ++ return true; ++#else ++ return false; // musl ++#endif ++} ++ ++static const size_t retain_size = 2 * M; ++ ++bool os::should_trim_native_heap() { ++#ifdef __GLIBC__ ++ bool rc = true; ++ // We try, using mallinfo, to predict whether a malloc_trim(3) will be beneficial. ++ // ++ // "mallinfo::keepcost" is no help even if manpage claims this to be the projected ++ // trim size. In practice it is just a very small value with no relation to the actual ++ // effect trimming will have. ++ // ++ // Our best bet is "mallinfo::fordblks", the total chunk size of free blocks. Since ++ // only free blocks can be trimmed, a very low bar is to require their combined size ++ // to be higher than our retain size. Note, however, that "mallinfo::fordblks" includes ++ // already-trimmed blocks, since glibc trims by calling madvice(MADV_DONT_NEED) on free ++ // chunks but does not update its bookkeeping. ++ // ++ // In the end we want to prevent obvious bogus attempts to trim, and for that fordblks ++ // is good enough. ++ os::Linux::glibc_mallinfo2 mi; ++ os::Linux::mallinfo_retval_t mirc = os::Linux::get_mallinfo(&mi); ++ const size_t total_free = mi.fordblks; ++ if (mirc == os::Linux::ok) { ++ rc = retain_size < total_free; ++ } ++ return rc; ++#else ++ return false; // musl ++#endif ++} ++ ++bool os::trim_native_heap(os::size_change_t* rss_change) { ++#ifdef __GLIBC__ ++ os::Linux::meminfo_t info1; ++ os::Linux::meminfo_t info2; ++ ++ bool have_info1 = os::Linux::query_process_memory_info(&info1); ++ ::malloc_trim(retain_size); ++ bool have_info2 = have_info1 && os::Linux::query_process_memory_info(&info2); ++ ++ if (have_info1 && have_info2 && ++ info1.vmrss != -1 && info2.vmrss != -1 && ++ info1.vmswap != -1 && info2.vmswap != -1) { ++ // Note: query_process_memory_info returns values in K ++ rss_change->before = (info1.vmrss + info1.vmswap) * K; ++ rss_change->after = (info2.vmrss + info2.vmswap) * K; ++ } else { ++ rss_change->after = rss_change->before = SIZE_MAX; ++ } ++ ++ return true; ++#else ++ return false; // musl ++#endif ++} +\ No newline at end of file +diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp +index 2bb3fd2..6c27bcb 100644 +--- a/hotspot/src/os/linux/vm/os_linux.hpp ++++ b/hotspot/src/os/linux/vm/os_linux.hpp +@@ -243,7 +243,7 @@ class Linux { + public: + static pthread_condattr_t* condAttr() { return _condattr; } + +- // Output structure for query_process_memory_info() ++ // Output structure for query_process_memory_info() (all values in KB) + struct meminfo_t { + ssize_t vmsize; // current virtual size + ssize_t vmpeak; // peak virtual size +@@ -338,40 +338,6 @@ private: + }; + static NumaAllocationPolicy _current_numa_policy; + +-#ifdef __GLIBC__ +- struct glibc_mallinfo { +- int arena; +- int ordblks; +- int smblks; +- int hblks; +- int hblkhd; +- int usmblks; +- int fsmblks; +- int uordblks; +- int fordblks; +- int keepcost; +- }; +- +- struct glibc_mallinfo2 { +- size_t arena; +- size_t ordblks; +- size_t smblks; +- size_t hblks; +- size_t hblkhd; +- size_t usmblks; +- size_t fsmblks; +- size_t uordblks; +- size_t fordblks; +- size_t keepcost; +- }; +- +- typedef struct glibc_mallinfo (*mallinfo_func_t)(void); +- typedef struct glibc_mallinfo2 (*mallinfo2_func_t)(void); +- +- static mallinfo_func_t _mallinfo; +- static mallinfo2_func_t _mallinfo2; +-#endif +- + public: + static int sched_getcpu() { return _sched_getcpu != NULL ? _sched_getcpu() : -1; } + static int numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) { +@@ -484,6 +450,27 @@ public: + return false; + } + } ++ ++#ifdef __GLIBC__ ++ struct glibc_mallinfo2 { ++ size_t arena; ++ size_t ordblks; ++ size_t smblks; ++ size_t hblks; ++ size_t hblkhd; ++ size_t usmblks; ++ size_t fsmblks; ++ size_t uordblks; ++ size_t fordblks; ++ size_t keepcost; ++ }; ++ enum mallinfo_retval_t { ok, error, ok_but_possibly_wrapped }; ++ // get_mallinfo() is a wrapper for mallinfo/mallinfo2. It will prefer mallinfo2() if found. ++ // If we only have mallinfo(), values may be 32-bit truncated, which is signaled via ++ // "ok_but_possibly_wrapped". ++ static mallinfo_retval_t get_mallinfo(glibc_mallinfo2* out); ++#endif ++ + }; + + +diff --git a/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp b/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp +index 95d03d9..39d47a3 100644 +--- a/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp ++++ b/hotspot/src/os/linux/vm/trimCHeapDCmd.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2021 SAP SE. All rights reserved. ++ * Copyright (c) 2022 SAP SE. All rights reserved. + * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * +@@ -25,53 +25,28 @@ + + #include "precompiled.hpp" + #include "runtime/os.hpp" ++#include "trimCHeapDCmd.hpp" + #include "utilities/debug.hpp" + #include "utilities/ostream.hpp" +-#include "trimCHeapDCmd.hpp" ++#include "utilities/globalDefinitions.hpp" + + #include + + void TrimCLibcHeapDCmd::execute(DCmdSource source, TRAPS) { +-#ifdef __GLIBC__ +- stringStream ss_report(1024); // Note: before calling trim +- +- os::Linux::meminfo_t info1; +- os::Linux::meminfo_t info2; +- // Query memory before... +- bool have_info1 = os::Linux::query_process_memory_info(&info1); +- +- _output->print_cr("Attempting trim..."); +- ::malloc_trim(0); +- _output->print_cr("Done."); +- +- // ...and after trim. +- bool have_info2 = os::Linux::query_process_memory_info(&info2); +- +- // Print report both to output stream as well to UL +- bool wrote_something = false; +- if (have_info1 && have_info2) { +- if (info1.vmsize != -1 && info2.vmsize != -1) { +- ss_report.print_cr("Virtual size before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)", +- info1.vmsize, info2.vmsize, (info2.vmsize - info1.vmsize)); +- wrote_something = true; +- } +- if (info1.vmrss != -1 && info2.vmrss != -1) { +- ss_report.print_cr("RSS before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)", +- info1.vmrss, info2.vmrss, (info2.vmrss - info1.vmrss)); +- wrote_something = true; +- } +- if (info1.vmswap != -1 && info2.vmswap != -1) { +- ss_report.print_cr("Swap before: " SSIZE_FORMAT "k, after: " SSIZE_FORMAT "k, (" SSIZE_FORMAT "k)", +- info1.vmswap, info2.vmswap, (info2.vmswap - info1.vmswap)); +- wrote_something = true; ++ if (os::can_trim_native_heap()) { ++ os::size_change_t sc; ++ if (os::trim_native_heap(&sc)) { ++ _output->print("Trim native heap: "); ++ if (sc.after != SIZE_MAX) { ++ const size_t delta = sc.after < sc.before ? (sc.before - sc.after) : (sc.after - sc.before); ++ const char sign = sc.after < sc.before ? '-' : '+'; ++ _output->print_cr("RSS+Swap: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ")", ++ PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta)); ++ } else { ++ _output->print_cr("(no details available)."); ++ } + } ++ } else { ++ _output->print_cr("Not available."); + } +- if (!wrote_something) { +- ss_report.print_raw("No details available."); +- } +- +- _output->print_raw(ss_report.base()); +-#else +- _output->print_cr("Not available."); +-#endif + } +diff --git a/hotspot/src/os/windows/vm/os_windows.cpp b/hotspot/src/os/windows/vm/os_windows.cpp +index 500a412..25122de 100644 +--- a/hotspot/src/os/windows/vm/os_windows.cpp ++++ b/hotspot/src/os/windows/vm/os_windows.cpp +@@ -5957,3 +5957,7 @@ void TestReserveMemorySpecial_test() { + } + #endif // PRODUCT + ++// stubbed-out trim-native support ++bool os::can_trim_native_heap() { return false; } ++bool os::should_trim_native_heap() { return false; } ++bool os::trim_native_heap(os::size_change_t* rss_change) { return false; } +\ No newline at end of file +diff --git a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +index ba156a2..7188925 100644 +--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp ++++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp +@@ -53,6 +53,7 @@ + #include "gc_implementation/shared/gcTimer.hpp" + #include "gc_implementation/shared/gcTrace.hpp" + #include "gc_implementation/shared/gcTraceTime.hpp" ++#include "gc_implementation/shared/gcTrimNativeHeap.hpp" + #include "gc_implementation/shared/isGCActiveMark.hpp" + #include "memory/allocation.hpp" + #include "memory/heapInspection.hpp" +@@ -1304,6 +1305,9 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, + TraceCollectorStats tcs(g1mm()->full_collection_counters()); + TraceMemoryManagerStats tms(true /* fullGC */, gc_cause()); + ++ // Pause native trimming for the duration of the GC ++ GCTrimNative::pause_periodic_trim(); ++ + double start = os::elapsedTime(); + g1_policy()->record_full_collection_start(); + +@@ -1546,6 +1550,8 @@ bool G1CollectedHeap::do_collection(bool explicit_gc, + + gc_timer->register_gc_end(); + gc_tracer->report_gc_end(gc_timer->gc_end(), gc_timer->time_partitions()); ++ ++ GCTrimNative::schedule_trim(); + } + return true; + } +diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +index 74c1584..1c47125 100644 +--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp ++++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/parallelScavengeHeap.cpp +@@ -36,6 +36,7 @@ + #include "gc_implementation/parallelScavenge/psScavenge.hpp" + #include "gc_implementation/parallelScavenge/vmPSOperations.hpp" + #include "gc_implementation/shared/gcHeapSummary.hpp" ++#include "gc_implementation/shared/gcTrimNativeHeap.hpp" + #include "gc_implementation/shared/gcWhen.hpp" + #include "memory/gcLocker.inline.hpp" + #include "oops/oop.inline.hpp" +@@ -147,6 +148,8 @@ void ParallelScavengeHeap::post_initialize() { + PSMarkSweep::initialize(); + } + PSPromotionManager::initialize(); ++ ++ GCTrimNative::initialize(true); + } + + void ParallelScavengeHeap::update_counters() { +diff --git a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +index 3f103ee..26d64a1 100644 +--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp ++++ b/hotspot/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp +@@ -42,6 +42,7 @@ + #include "gc_implementation/shared/gcTimer.hpp" + #include "gc_implementation/shared/gcTrace.hpp" + #include "gc_implementation/shared/gcTraceTime.hpp" ++#include "gc_implementation/shared/gcTrimNativeHeap.hpp" + #include "gc_implementation/shared/isGCActiveMark.hpp" + #include "gc_interface/gcCause.hpp" + #include "memory/gcLocker.inline.hpp" +@@ -2008,6 +2009,9 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { + return false; + } + ++ // Pause native trimming for the duration of the GC ++ GCTrimNative::pause_periodic_trim(); ++ + ParallelScavengeHeap* heap = gc_heap(); + + _gc_timer.register_gc_start(); +@@ -2182,6 +2186,8 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { + // Resize the metaspace capactiy after a collection + MetaspaceGC::compute_new_size(); + ++ GCTrimNative::schedule_trim(); ++ + if (TraceGen1Time) accumulated_time()->stop(); + + if (PrintGC) { +diff --git a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp +index e39fd7a..024499a 100644 +--- a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp ++++ b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * 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,12 +40,12 @@ ConcurrentGCThread::ConcurrentGCThread() : + _should_terminate(false), _has_terminated(false) { + }; + +-void ConcurrentGCThread::create_and_start() { ++void ConcurrentGCThread::create_and_start(ThreadPriority prio) { + if (os::create_thread(this, os::cgc_thread)) { + // XXX: need to set this to low priority + // unless "agressive mode" set; priority + // should be just less than that of VMThread. +- os::set_priority(this, NearMaxPriority); ++ os::set_priority(this, prio); + if (!_should_terminate && !DisableStartThread) { + os::start_thread(this); + } +@@ -63,7 +63,7 @@ void ConcurrentGCThread::initialize_in_thread() { + void ConcurrentGCThread::wait_for_universe_init() { + MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); + while (!is_init_completed() && !_should_terminate) { +- CGC_lock->wait(Mutex::_no_safepoint_check_flag, 200); ++ CGC_lock->wait(Mutex::_no_safepoint_check_flag, 1); + } + } + +diff --git a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp +index e87228b..1e16bf7 100644 +--- a/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp ++++ b/hotspot/src/share/vm/gc_implementation/shared/concurrentGCThread.hpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -33,7 +33,7 @@ class ConcurrentGCThread: public NamedThread { + friend class VMStructs; + + protected: +- bool _should_terminate; ++ bool volatile _should_terminate; + bool _has_terminated; + + enum CGC_flag_type { +@@ -50,7 +50,7 @@ protected: + static int reset_CGC_flag(int b) { return _CGC_flag &= ~b; } + + // Create and start the thread (setting it's priority high.) +- void create_and_start(); ++ void create_and_start(ThreadPriority prio = NearMaxPriority); + + // Do initialization steps in the thread: record stack base and size, + // init thread local storage, set JNI handle block. +diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.cpp b/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.cpp +new file mode 100644 +index 0000000..b9bac56 +--- /dev/null ++++ b/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.cpp +@@ -0,0 +1,246 @@ ++/* ++ * Copyright (c) 2022 SAP SE. All rights reserved. ++ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * ++ * This code is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License version 2 only, as ++ * published by the Free Software Foundation. ++ * ++ * This code is distributed in the hope that it will be useful, but WITHOUT ++ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ++ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ * version 2 for more details (a copy is included in the LICENSE file that ++ * accompanied this code). ++ * ++ * You should have received a copy of the GNU General Public License version ++ * 2 along with this work; if not, write to the Free Software Foundation, ++ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ++ * ++ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ++ * or visit www.oracle.com if you need additional information or have any ++ * questions. ++ * ++ */ ++ ++#include "precompiled.hpp" ++#include "gc_implementation/shared/concurrentGCThread.hpp" ++#include "gc_implementation/shared/gcTrimNativeHeap.hpp" ++#include "gc_implementation/g1/g1_globals.hpp" ++#include "runtime/globals.hpp" ++#include "runtime/globals_extension.hpp" ++#include "runtime/mutex.hpp" ++#include "runtime/mutexLocker.hpp" ++#include "runtime/os.hpp" ++#include "utilities/debug.hpp" ++#include "utilities/globalDefinitions.hpp" ++#include "utilities/ostream.hpp" ++#include "utilities/ticks.hpp" ++ ++bool GCTrimNative::_async_mode = false; ++double GCTrimNative::_next_trim_not_before = 0; ++ ++// GCTrimNative works in two modes: ++// ++// - async mode, where GCTrimNative runs a trimmer thread on behalf of the GC. ++// The trimmer thread will be doing all the trims, both periodically and ++// triggered from outside via GCTrimNative::schedule_trim(). ++// ++// - synchronous mode, where the GC does the trimming itself in its own thread, ++// via GCTrimNative::should_trim() and GCTrimNative::execute_trim(). ++// ++// The mode is set as argument to GCTrimNative::initialize(). ++ ++class NativeTrimmer : public ConcurrentGCThread { ++ ++ Monitor* _lock; ++ volatile jlong _paused; ++ static NativeTrimmer* _the_trimmer; ++ ++public: ++ ++ virtual void run() { ++ initialize_in_thread(); ++ wait_for_universe_init(); ++ ++ assert(GCTrimNativeHeap, "Sanity"); ++ assert(os::can_trim_native_heap(), "Sanity"); ++ ++ gclog_or_tty->print_cr("NativeTrimmer started."); ++ ++ // Note: GCTrimNativeHeapInterval=0 -> zero wait time -> indefinite waits, disabling periodic trim ++ const int64_t delay_ms = GCTrimNativeHeapInterval * 1000; ++ for (;;) { ++ MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag); ++ ml.wait(Mutex::_no_safepoint_check_flag, delay_ms); ++ if (_should_terminate) { ++ gclog_or_tty->print_cr("NativeTrimmer stopped."); ++ break; ++ } ++ jlong paused = Atomic::load(&_paused); ++ if (!paused && os::should_trim_native_heap()) { ++ GCTrimNative::do_trim(); ++ } ++ } ++ ++ terminate(); ++ } ++ ++ void stop() { ++ { ++ MutexLockerEx ml(Terminator_lock); ++ _should_terminate = true; ++ } ++ ++ wakeup(); ++ ++ { ++ MutexLockerEx ml(Terminator_lock); ++ while (!_has_terminated) { ++ Terminator_lock->wait(); ++ } ++ } ++ } ++ ++protected: ++ ++ void wakeup() { ++ MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag); ++ ml.notify_all(); ++ } ++ ++ void pause() { ++ Atomic::store(1, &_paused); ++ debug_only(gclog_or_tty->print_cr("NativeTrimmer paused")); ++ } ++ ++ void unpause() { ++ Atomic::store(0, &_paused); ++ debug_only(gclog_or_tty->print_cr("NativeTrimmer unpaused")); ++ } ++ ++public: ++ ++ NativeTrimmer() : ++ _paused(0) ++ { ++ //Mutex::leaf+8 just for NativeTrimmer_lock ++ _lock = new (std::nothrow) Monitor(Mutex::leaf+8, "NativeTrimmer_lock", true); ++ set_name("NativeTrimmer Thread"); ++ } ++ ++ static bool is_enabled() { ++ return _the_trimmer != NULL; ++ } ++ ++ static void start_trimmer() { ++ _the_trimmer = new NativeTrimmer(); ++ _the_trimmer->create_and_start(NormPriority); ++ } ++ ++ static void stop_trimmer() { ++ _the_trimmer->stop(); ++ } ++ ++ static void pause_periodic_trim() { ++ _the_trimmer->pause(); ++ } ++ ++ static void unpause_periodic_trim() { ++ _the_trimmer->unpause(); ++ } ++ ++ static void schedule_trim_now() { ++ _the_trimmer->unpause(); ++ _the_trimmer->wakeup(); ++ } ++ ++}; // NativeTrimmer ++ ++NativeTrimmer* NativeTrimmer::_the_trimmer = NULL; ++ ++void GCTrimNative::do_trim() { ++ Ticks start = Ticks::now(); ++ os::size_change_t sc; ++ if (os::trim_native_heap(&sc)) { ++ Tickspan trim_time = (Ticks::now() - start); ++ if (sc.after != SIZE_MAX) { ++ const size_t delta = sc.after < sc.before ? (sc.before - sc.after) : (sc.after - sc.before); ++ const char sign = sc.after < sc.before ? '-' : '+'; ++ gclog_or_tty->print_cr("Trim native heap: RSS+Swap: " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT "), %1.3fms", ++ PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta), ++ trim_time.seconds() * 1000); ++ } else { ++ gclog_or_tty->print_cr("Trim native heap (no details)"); ++ } ++ } ++} ++ ++/// GCTrimNative outside facing methods ++ ++void GCTrimNative::initialize(bool async_mode) { ++ ++ if (GCTrimNativeHeap) { ++ ++ if (!os::can_trim_native_heap()) { ++ FLAG_SET_ERGO(bool, GCTrimNativeHeap, false); ++ gclog_or_tty->print_cr("GCTrimNativeHeap disabled - trim-native not supported on this platform."); ++ return; ++ } ++ ++ debug_only(gclog_or_tty->print_cr("GCTrimNativeHeap enabled.")); ++ ++ _async_mode = async_mode; ++ ++ // If we are to run the trimmer on behalf of the GC: ++ if (_async_mode) { ++ NativeTrimmer::start_trimmer(); ++ } ++ ++ _next_trim_not_before = GCTrimNativeHeapInterval; ++ } ++} ++ ++void GCTrimNative::cleanup() { ++ if (GCTrimNativeHeap) { ++ if (_async_mode) { ++ NativeTrimmer::stop_trimmer(); ++ } ++ } ++} ++ ++bool GCTrimNative::should_trim(bool ignore_delay) { ++ return ++ GCTrimNativeHeap && os::can_trim_native_heap() && ++ (ignore_delay || (GCTrimNativeHeapInterval > 0 && os::elapsedTime() > _next_trim_not_before)) && ++ os::should_trim_native_heap(); ++} ++ ++void GCTrimNative::execute_trim() { ++ if (GCTrimNativeHeap) { ++ assert(!_async_mode, "Only call for non-async mode"); ++ do_trim(); ++ _next_trim_not_before = os::elapsedTime() + GCTrimNativeHeapInterval; ++ } ++} ++ ++void GCTrimNative::pause_periodic_trim() { ++ if (GCTrimNativeHeap) { ++ assert(_async_mode, "Only call for async mode"); ++ NativeTrimmer::pause_periodic_trim(); ++ } ++} ++ ++void GCTrimNative::unpause_periodic_trim() { ++ if (GCTrimNativeHeap) { ++ assert(_async_mode, "Only call for async mode"); ++ NativeTrimmer::unpause_periodic_trim(); ++ } ++} ++ ++void GCTrimNative::schedule_trim() { ++ if (GCTrimNativeHeap) { ++ assert(_async_mode, "Only call for async mode"); ++ NativeTrimmer::schedule_trim_now(); ++ } ++} +diff --git a/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.hpp b/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.hpp +new file mode 100644 +index 0000000..f586093 +--- /dev/null ++++ b/hotspot/src/share/vm/gc_implementation/shared/gcTrimNativeHeap.hpp +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (c) 2022 SAP SE. All rights reserved. ++ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * 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 SHARE_GC_SHARED_GCTRIMNATIVEHEAP_HPP ++#define SHARE_GC_SHARED_GCTRIMNATIVEHEAP_HPP ++ ++#include "memory/allocation.hpp" ++ ++class NativeTrimmer; ++ ++class GCTrimNative : public AllStatic { ++ friend class NativeTrimmer; ++ ++ static bool _async_mode; ++ static double _next_trim_not_before; ++ ++ static void do_trim(); ++ ++public: ++ ++ static void initialize(bool async_mode); ++ static void cleanup(); ++ ++ // Returns true if: ++ // - trimming is enabled and possible ++ // - trimming may have an actual effect (guess) ++ // - delay timer has expired (unless ignore_delay is true) ++ static bool should_trim(bool ignore_delay); ++ ++ // Execute trim-native in this thread ++ static void execute_trim(); ++ ++ // Pause/unpause periodic trim ++ static void pause_periodic_trim(); ++ static void unpause_periodic_trim(); ++ ++ // Schedule an explicit trim now; if periodic trims had been ++ // paused, they are unpaused. ++ static void schedule_trim(); ++ ++}; ++ ++#endif // SHARE_GC_SHARED_GCTRIMNATIVEHEAP_HPP +diff --git a/hotspot/src/share/vm/memory/genCollectedHeap.cpp b/hotspot/src/share/vm/memory/genCollectedHeap.cpp +index 20fbbfd..7df3d68 100644 +--- a/hotspot/src/share/vm/memory/genCollectedHeap.cpp ++++ b/hotspot/src/share/vm/memory/genCollectedHeap.cpp +@@ -58,6 +58,7 @@ + #if INCLUDE_ALL_GCS + #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" + #include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp" ++#include "gc_implementation/shared/gcTrimNativeHeap.hpp" + #endif // INCLUDE_ALL_GCS + #if INCLUDE_JFR + #include "jfr/jfr.hpp" +@@ -572,6 +573,11 @@ void GenCollectedHeap::do_collection(bool full, + update_full_collections_completed(); + } + ++ // Trim the native heap, without a delay since this is a full gc ++ if (full && GCTrimNative::should_trim(true)) { ++ GCTrimNative::execute_trim(); ++ } ++ + // Track memory usage and detect low memory after GC finishes + MemoryService::track_memory_usage(); + +diff --git a/hotspot/src/share/vm/memory/sharedHeap.cpp b/hotspot/src/share/vm/memory/sharedHeap.cpp +index ef22f01..8c02320 100644 +--- a/hotspot/src/share/vm/memory/sharedHeap.cpp ++++ b/hotspot/src/share/vm/memory/sharedHeap.cpp +@@ -26,6 +26,7 @@ + #include "classfile/symbolTable.hpp" + #include "classfile/systemDictionary.hpp" + #include "code/codeCache.hpp" ++#include "gc_implementation/shared/gcTrimNativeHeap.hpp" + #include "gc_interface/collectedHeap.inline.hpp" + #include "memory/sharedHeap.hpp" + #include "oops/oop.inline.hpp" +@@ -104,6 +105,11 @@ void SharedHeap::set_barrier_set(BarrierSet* bs) { + void SharedHeap::post_initialize() { + CollectedHeap::post_initialize(); + ref_processing_init(); ++ if (!UseSerialGC) { ++ GCTrimNative::initialize(true); ++ } else { ++ GCTrimNative::initialize(false); // false since we will call trim inside the collecting thread ++ } + } + + void SharedHeap::ref_processing_init() {} +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 0dab18e..ec48c48 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -3387,6 +3387,16 @@ class CommandLineFlags { + "Number of entries we will try to leave on the stack " \ + "during parallel gc") \ + \ ++ experimental(bool, GCTrimNativeHeap, false, \ ++ "GC will attempt to trim the native heap periodically and at " \ ++ "full GCs.") \ ++ \ ++ experimental(uintx, GCTrimNativeHeapInterval, 60, \ ++ "If GCTrimNativeHeap is enabled: interval time, in seconds, in " \ ++ "which the VM will attempt to trim the native heap. A value of " \ ++ "0 disables periodic trimming while leaving trimming at full gc " \ ++ "enabled.") \ ++ \ + /* stack parameters */ \ + product_pd(intx, StackYellowPages, \ + "Number of yellow zone (recoverable overflows) pages") \ +diff --git a/hotspot/src/share/vm/runtime/init.cpp b/hotspot/src/share/vm/runtime/init.cpp +index d15e40d..d2e0f22 100644 +--- a/hotspot/src/share/vm/runtime/init.cpp ++++ b/hotspot/src/share/vm/runtime/init.cpp +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -166,8 +166,7 @@ void exit_globals() { + } + } + +- +-static bool _init_completed = false; ++static volatile bool _init_completed = false; + + bool is_init_completed() { + return _init_completed; +diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp +index 4f290c8..54b980d 100644 +--- a/hotspot/src/share/vm/runtime/java.cpp ++++ b/hotspot/src/share/vm/runtime/java.cpp +@@ -30,6 +30,7 @@ + #include "code/codeCache.hpp" + #include "compiler/compileBroker.hpp" + #include "compiler/compilerOracle.hpp" ++#include "gc_implementation/shared/gcTrimNativeHeap.hpp" + #include "interpreter/bytecodeHistogram.hpp" + #include "jfr/jfrEvents.hpp" + #include "jfr/support/jfrThreadId.hpp" +@@ -509,6 +510,8 @@ void before_exit(JavaThread * thread) { + StatSampler::disengage(); + StatSampler::destroy(); + ++ GCTrimNative::cleanup(); ++ + // Stop concurrent GC threads + Universe::heap()->stop(); + +diff --git a/hotspot/src/share/vm/runtime/os.hpp b/hotspot/src/share/vm/runtime/os.hpp +index 7ae49fd..acc57f4 100644 +--- a/hotspot/src/share/vm/runtime/os.hpp ++++ b/hotspot/src/share/vm/runtime/os.hpp +@@ -333,6 +333,17 @@ class os: AllStatic { + static bool uncommit_memory(char* addr, size_t bytes); + static bool release_memory(char* addr, size_t bytes); + ++ // Does the platform support trimming the native heap? ++ static bool can_trim_native_heap(); ++ ++ // Does the platform recommend trimming? ++ static bool should_trim_native_heap(); ++ ++ // Trim the C-heap. Returns RSS size change and optionally return the rss size change. ++ // If trim was done but size change could not be obtained, SIZE_MAX is returned for after size. ++ struct size_change_t { size_t before; size_t after; }; ++ static bool trim_native_heap(size_change_t* rss_change); ++ + // Touch memory pages that cover the memory range from start to end (exclusive) + // to make the OS back the memory range with actual memory. + // Current implementation may not touch the last page if unaligned addresses +diff --git a/hotspot/src/share/vm/utilities/globalDefinitions.hpp b/hotspot/src/share/vm/utilities/globalDefinitions.hpp +index 25f6f02..12eea20 100644 +--- a/hotspot/src/share/vm/utilities/globalDefinitions.hpp ++++ b/hotspot/src/share/vm/utilities/globalDefinitions.hpp +@@ -260,6 +260,9 @@ inline T byte_size_in_proper_unit(T s) { + } + } + ++#define PROPERFMT SIZE_FORMAT "%s" ++#define PROPERFMTARGS(S) byte_size_in_proper_unit(S), proper_unit_for_byte_size(S) ++ + //---------------------------------------------------------------------------------------------------- + // VM type definitions + +diff --git a/hotspot/test/gc/TestTrimNative.java b/hotspot/test/gc/TestTrimNative.java +new file mode 100644 +index 0000000..58d5405 +--- /dev/null ++++ b/hotspot/test/gc/TestTrimNative.java +@@ -0,0 +1,435 @@ ++/* ++ * Copyright (c) 2022 SAP SE. All rights reserved. ++ * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2022, Huawei Technologies Co., Ltd. All rights reserved. ++ * 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 gc; ++ ++/* ++ * All these tests test the trim-native feature for all GCs. ++ * Trim-native is the ability to trim the C-heap as part of the GC cycle. ++ * This feature is controlled by -XX:+GCTrimNativeHeap (by default off). ++ * Trimming happens on full gc for all gcs. Shenandoah and G1 also support ++ * concurrent trimming (Shenandoah supports this without any ties to java ++ * heap occupancy). ++ * ++ */ ++ ++//// full gc tests ///// ++ ++/* ++ * @test id=fullgc-serial ++ * @summary Test that GCTrimNativeHeap works with Serial ++ * @requires vm.gc=="Serial" ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-fullgc serial ++ */ ++ ++/* ++ * @test id=fullgc-parallel ++ * @summary Test that GCTrimNativeHeap works with Parallel ++ * @requires vm.gc=="Parallel" ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-fullgc parallel ++ */ ++ ++/* ++ * @test id=fullgc-g1 ++ * @summary Test that GCTrimNativeHeap works with G1 ++ * @requires vm.gc=="G1" ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-fullgc g1 ++ */ ++ ++//// auto mode tests ///// ++ ++// Note: not serial, since it does not do periodic trimming, only trimming on full gc ++ ++/* ++ * @test id=auto-parallel ++ * @summary Test that GCTrimNativeHeap works with Parallel ++ * @requires vm.gc=="Parallel" ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-auto parallel ++ */ ++ ++/* ++ * @test id=auto-g1 ++ * @summary Test that GCTrimNativeHeap works with G1 ++ * @requires vm.gc=="G1" ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-auto g1 ++ */ ++ ++ ++//// test-auto-high-interval interval test ///// ++ ++// Note: not serial, since it does not do periodic trimming, only trimming on full gc ++ ++/* ++ * @test id=auto-high-interval-parallel ++ * @summary Test that a high GCTrimNativeHeapInterval effectively disables automatic trimming ++ * @requires vm.gc=="Parallel" ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-auto-high-interval parallel ++ */ ++ ++/* ++ * @test id=auto-high-interval-g1 ++ * @summary Test that a high GCTrimNativeHeapInterval effectively disables automatic trimming ++ * @requires vm.gc=="G1" ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-auto-high-interval g1 ++ */ ++ ++//// test-auto-interval-0 test ///// ++ ++// Note: not serial, since it does not do periodic trimming, only trimming on full gc ++ ++/* ++ * @test id=auto-zero-interval-parallel ++ * @summary Test that a GCTrimNativeHeapInterval=0 disables periodic trimming ++ * @requires vm.gc=="Parallel" ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-auto-zero-interval parallel ++ */ ++ ++/* ++ * @test id=auto-zero-interval-g1 ++ * @summary Test that a GCTrimNativeHeapInterval=0 disables periodic trimming ++ * @requires vm.gc=="G1" ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-auto-zero-interval g1 ++ */ ++ ++// Other tests ++ ++/* ++ * @test id=off-explicit ++ * @summary Test that -GCTrimNative disables the feature ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-off-explicit ++ */ ++ ++/* ++ * @test id=off-by-default ++ * @summary Test that GCTrimNative is off by default ++ * @requires os.family=="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-off-by-default ++ */ ++ ++/* ++ * @test id=off-on-other-platforms ++ * @summary Test that GCTrimNative is off on unsupportive platforms ++ * @requires os.family!="linux" ++ * @modules java.base/jdk.internal.misc ++ * @library /testlibrary ++ * @run driver gc.TestTrimNative test-off-on-other-platforms ++ */ ++ ++import sun.misc.Unsafe; ++import com.oracle.java.testlibrary.*; ++ ++import java.lang.reflect.Field; ++import java.util.*; ++import java.util.regex.Matcher; ++import java.util.regex.Pattern; ++ ++public class TestTrimNative { ++ ++ // Actual RSS increase is a lot larger than 4 MB. Depends on glibc overhead, and NMT malloc headers in debug VMs. ++ // We need small-grained allocations to make sure they actually increase RSS (all touched) and to see the ++ // glibc-retaining-memory effect. ++ static final int szAllocations = 16; ++ static final int totalAllocationsSize = 16 * 1024 * 1024; // 16 MB total ++ static final int numAllocations = totalAllocationsSize / szAllocations; ++ ++ static long[] ptrs = new long[numAllocations]; ++ ++ enum Unit { ++ B(1), K(1024), M(1024*1024), G(1024*1024*1024); ++ public final long size; ++ Unit(long size) { this.size = size; } ++ } ++ ++ enum GC { ++ serial, parallel, g1, shenandoah, z; ++ String getSwitchName() { ++ String s = name(); ++ return "-XX:+Use" + s.substring(0, 1).toUpperCase() + s.substring(1) + "GC"; ++ } ++ boolean isZ() { return this == GC.z; } ++ boolean isSerial() { return this == GC.serial; } ++ boolean isParallel() { return this == GC.parallel; } ++ boolean isG1() { return this == GC.g1; } ++ boolean isShenandoah() { return this == GC.shenandoah; } ++ } ++ ++ static private boolean usesNativeTrimmer(GC gc) { ++ return gc.isG1() || gc.isParallel() || gc.isZ(); ++ } ++ ++ static private final OutputAnalyzer runTestWithOptions(String[] extraOptions, String[] testArgs) throws Exception { ++ ++ List allOptions = new ArrayList(); ++ allOptions.add("-XX:+UnlockExperimentalVMOptions"); ++ allOptions.addAll(Arrays.asList(extraOptions)); ++ allOptions.add("-Xmx128m"); ++ allOptions.add("-Xms128m"); // Stabilize RSS ++ allOptions.add("-XX:+AlwaysPreTouch"); // Stabilize RSS ++ ++ allOptions.add(TestTrimNative.class.getName()); ++ allOptions.add("RUN"); ++ allOptions.addAll(Arrays.asList(testArgs)); ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(allOptions.toArray(new String[0])); ++ OutputAnalyzer output = new OutputAnalyzer(pb.start()); ++ output.shouldHaveExitValue(0); ++ return output; ++ ++ } ++ ++ /** ++ * Given JVM output, look for a log line that describes a successful negative trim in the megabyte range ++ * like this: ++ * "[2.053s][debug][gc,trim] Trim native heap (retain size: 5120K): RSS+Swap: 271M->223M (-49112K), 2.834ms" ++ * (Note: we use the "properXXX" print routines, therefore units can differ) ++ * Check that the sum of all trim log lines comes to a total RSS reduction in the MB range ++ * @param output ++ * @param minExpected min number of trim lines expected in UL log ++ * @param maxExpected max number of trim lines expected in UL log ++ */ ++ private final static void parseOutputAndLookForNegativeTrim(OutputAnalyzer output, int minExpected, int maxExpected) { ++ output.reportDiagnosticSummary(); ++ List lines = output.asLines(); ++ Pattern pat = Pattern.compile(".*\\[gc,trim\\] Trim native heap.*RSS\\+Swap: (\\d+)([KMB])->(\\d+)([KMB]).*"); ++ int numTrimsFound = 0; ++ long rssReductionTotal = 0; ++ for (String line : lines) { ++ Matcher mat = pat.matcher(line); ++ if (mat.matches()) { ++ long rss1 = Long.parseLong(mat.group(1)) * Unit.valueOf(mat.group(2)).size; ++ long rss2 = Long.parseLong(mat.group(3)) * Unit.valueOf(mat.group(4)).size; ++ System.out.println("Parsed Trim Line. rss1: " + rss1 + " rss2: " + rss2); ++ if (rss1 > rss2) { ++ rssReductionTotal += (rss1 - rss2); ++ } ++ numTrimsFound ++; ++ } ++ if (numTrimsFound > maxExpected) { ++ throw new RuntimeException("Abnormal high number of trim attempts found (more than " + maxExpected + ++ "). Does the interval setting not work?"); ++ } ++ } ++ if (numTrimsFound < minExpected) { ++ throw new RuntimeException("We found fewer trim lines in UL log than expected (expected " + minExpected + ++ ", found " + numTrimsFound + "."); ++ } ++ // This is very fuzzy. We malloced X, free'd X, trimmed, measured the combined effect of all reductions. ++ // This does not take into effect mallocs or frees that may happen concurrently. But we expect to see *some* ++ // reduction somewhere. Test with a fudge factor. ++ float fudge = 0.8f; ++ long expectedMinimalReduction = (long) (totalAllocationsSize * fudge); ++ if (rssReductionTotal < expectedMinimalReduction) { ++ throw new RuntimeException("We did not see the expected RSS reduction in the UL log. Expected (with fudge)" + ++ " to see at least a combined reduction of " + expectedMinimalReduction + "."); ++ } ++ } ++ ++ // Test that GCTrimNativeHeap=1 causes a trim-native on full gc ++ static private final void testWithFullGC(GC gc) throws Exception { ++ System.out.println("testWithFullGC"); ++ int sleeptime_secs = 2; ++ OutputAnalyzer output = runTestWithOptions ( ++ new String[] { gc.getSwitchName(), "-XX:+GCTrimNativeHeap" }, ++ new String[] { "true" /* full gc */, String.valueOf(sleeptime_secs * 1000) /* ms after peak */ } ++ ); ++ // With default interval time of 30 seconds, auto trimming should never kick in, so the only ++ // log line we expect to see is the one from the full-gc induced trim. ++ parseOutputAndLookForNegativeTrim(output, 1, 1); ++ // For GCs that use the NativeTrimmer, we want to see the NativeTrimmer paused during the GC, as well as ++ // started and shut down properly. ++ if (usesNativeTrimmer(gc)) { ++ output.shouldContain("NativeTrimmer started"); ++ output.shouldContain("NativeTrimmer paused"); ++ output.shouldContain("NativeTrimmer unpaused"); ++ output.shouldContain("NativeTrimmer stopped"); ++ } else { ++ output.shouldNotContain("NativeTrimmer"); ++ } ++ } ++ ++ // Test that GCTrimNativeHeap=1 causes a trim-native automatically, without GC (for now, shenandoah only) ++ static private final void testAuto(GC gc) throws Exception { ++ System.out.println("testAuto"); ++ long t1 = System.currentTimeMillis(); ++ int sleeptime_secs = 4; ++ OutputAnalyzer output = runTestWithOptions ( ++ new String[] { gc.getSwitchName(), "-XX:+GCTrimNativeHeap", "-XX:GCTrimNativeHeapInterval=1" }, ++ new String[] { "false" /* full gc */, String.valueOf(sleeptime_secs * 1000) /* ms after peak */ } ++ ); ++ long t2 = System.currentTimeMillis(); ++ int runtime_s = (int)((t2 - t1) / 1000); ++ // With an interval time of 1 second and a runtime of 6..x seconds we expect to see x log lines (+- fudge factor). ++ parseOutputAndLookForNegativeTrim(output, runtime_s - 4, runtime_s + 2); ++ } ++ ++ // Test that trim-native correctly honors interval ++ static private final void testAutoWithHighInterval(GC gc) throws Exception { ++ // We pass a very high interval. This should disable the feature for this short-lived test, we should see no trim ++ System.out.println("testAutoWithHighInterval"); ++ OutputAnalyzer output = runTestWithOptions ( ++ new String[] { gc.getSwitchName(), "-XX:+GCTrimNativeHeap", "-XX:GCTrimNativeHeapInterval=30" }, ++ new String[] { "false" /* full gc */, "6000" /* ms after peak */ } ++ ); ++ output.shouldNotContain("Trim native heap"); ++ } ++ ++ // Test that trim-native correctly honors interval ++ static private final void testAutoWithZeroInterval(GC gc) throws Exception { ++ // We pass a very high interval. This should disable the feature for this short-lived test, we should see no trim ++ System.out.println("testAutoWithHighInterval"); ++ OutputAnalyzer output = runTestWithOptions ( ++ new String[] { gc.getSwitchName(), "-XX:+GCTrimNativeHeap", "-XX:GCTrimNativeHeapInterval=0" }, ++ new String[] { "false" /* full gc */, "6000" /* ms after peak */ } ++ ); ++ output.shouldNotContain("Trim native heap"); ++ } ++ ++ // Test that trim-native gets disabled on platforms that don't support it. ++ static private final void testOffOnNonCompliantPlatforms() throws Exception { ++ // Logic is shared, so no need to test with every GC. Just use the default GC. ++ System.out.println("testOffOnNonCompliantPlatforms"); ++ OutputAnalyzer output = runTestWithOptions ( ++ new String[] { "-XX:+GCTrimNativeHeap" }, ++ new String[] { "true" /* full gc */, "2000" /* ms after peak */ } ++ ); ++ output.shouldContain("GCTrimNativeHeap disabled"); ++ output.shouldNotContain("Trim native heap"); ++ } ++ ++ // Test that GCTrimNativeHeap=0 switches trim-native off ++ static private final void testOffExplicit() throws Exception { ++ // Logic is shared, so no need to test with every GC. Just use the default GC. ++ System.out.println("testOffExplicit"); ++ OutputAnalyzer output = runTestWithOptions ( ++ new String[] { "-XX:-GCTrimNativeHeap" }, ++ new String[] { "true" /* full gc */, "2000" /* ms after peak */ } ++ ); ++ output.shouldNotContain("Trim native heap"); ++ } ++ ++ // Test that trim-native is disabled by default ++ static private final void testOffByDefault() throws Exception { ++ // Logic is shared, so no need to test with every GC. Just use the default GC. ++ System.out.println("testOffByDefault"); ++ OutputAnalyzer output = runTestWithOptions ( ++ new String[] { }, ++ new String[] { "true" /* full gc */, "2000" /* ms after peak */ } ++ ); ++ output.shouldNotContain("Trim native heap"); ++ } ++ ++ public static void main(String[] args) throws Exception { ++ ++ if (args.length == 0) { ++ throw new RuntimeException("Argument error"); ++ } ++ ++ if (args[0].equals("RUN")) { ++ boolean doFullGC = Boolean.parseBoolean(args[1]); ++ ++ System.out.println("Will spike now..."); ++ Field field = Unsafe.class.getDeclaredField("theUnsafe"); ++ field.setAccessible(true); ++ Unsafe unsafe = (Unsafe) field.get(null); ++ for (int i = 0; i < numAllocations; i++) { ++ ptrs[i] = unsafe.allocateMemory(szAllocations); ++ unsafe.putByte(ptrs[i], (byte)0); ++ unsafe.putByte(ptrs[i] + szAllocations / 2, (byte)0); ++ } ++ for (int i = 0; i < numAllocations; i++) { ++ unsafe.freeMemory(ptrs[i]); ++ } ++ System.out.println("Done spiking."); ++ ++ if (doFullGC) { ++ System.out.println("GC..."); ++ System.gc(); ++ } ++ ++ // give GC time to react ++ int time = Integer.parseInt(args[2]); ++ System.out.println("Sleeping..."); ++ Thread.sleep(time); ++ System.out.println("Done."); ++ ++ return; ++ ++ } else if (args[0].equals("test-fullgc")) { ++ final GC gc = GC.valueOf(args[1]); ++ testWithFullGC(gc); ++ } else if (args[0].equals("test-auto")) { ++ final GC gc = GC.valueOf(args[1]); ++ testAuto(gc); ++ } else if (args[0].equals("test-auto-high-interval")) { ++ final GC gc = GC.valueOf(args[1]); ++ testAutoWithHighInterval(gc); ++ } else if (args[0].equals("test-auto-zero-interval")) { ++ final GC gc = GC.valueOf(args[1]); ++ testAutoWithZeroInterval(gc); ++ } else if (args[0].equals("test-off-explicit")) { ++ testOffExplicit(); ++ } else if (args[0].equals("test-off-by-default")) { ++ testOffByDefault(); ++ } else if (args[0].equals("test-off-on-other-platforms")) { ++ testOffOnNonCompliantPlatforms(); ++ } else { ++ throw new RuntimeException("Invalid test " + args[0]); ++ } ++ ++ } ++ ++} +\ No newline at end of file +diff --git a/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java b/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java +index 0fe8e35..131fa4c 100644 +--- a/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java ++++ b/hotspot/test/serviceability/dcmd/TrimLibcHeapTest.java +@@ -29,7 +29,7 @@ import com.oracle.java.testlibrary.*; + * @test + * @summary Test of diagnostic command VM.trim_libc_heap + * @library /testlibrary +- * @requires os.family == "linux" ++ * @requires os.family=="linux" + * @modules java.base/jdk.internal.misc + * java.compiler + * java.management +@@ -40,10 +40,7 @@ public class TrimLibcHeapTest { + public void run(CommandExecutor executor) { + OutputAnalyzer output = executor.execute("System.trim_native_heap"); + output.reportDiagnosticSummary(); +- output.shouldMatch("(Done|Not available)"); // Not available could happen on Linux + non-glibc (eg. muslc) +- if (output.firstMatch("Done") != null) { +- output.shouldMatch("(Virtual size before|RSS before|Swap before|No details available)"); +- } ++ output.shouldMatch(".*Trim native heap: RSS\\+Swap: \\d+[BKM]->\\d+[BKM].*"); + } + + @Test +-- +1.8.3.1 diff --git a/8294357-tz-Update-Timezone-Data-to-2022d.patch b/8294357-tz-Update-Timezone-Data-to-2022d.patch new file mode 100644 index 0000000..2e10ad4 --- /dev/null +++ b/8294357-tz-Update-Timezone-Data-to-2022d.patch @@ -0,0 +1,526 @@ +From 78c19b03f00f61f673311cf3c70a21ce25933eec Mon Sep 17 00:00:00 2001 +From: eapen +Date: Wed, 30 Nov 2022 11:39:58 +0000 +Subject: [PATCH 07/33] I68TO2: 8294357: (tz) Update Timezone Data to 2022d +--- + jdk/make/data/tzdata/VERSION | 2 +- + jdk/make/data/tzdata/asia | 30 +++++++---- + jdk/make/data/tzdata/backward | 2 + + jdk/make/data/tzdata/europe | 58 ++++------------------ + jdk/make/data/tzdata/southamerica | 10 +++- + jdk/make/data/tzdata/zone.tab | 2 - + .../classes/sun/util/calendar/ZoneInfoFile.java | 9 +--- + jdk/test/java/util/TimeZone/TimeZoneData/VERSION | 2 +- + .../java/util/TimeZone/TimeZoneData/aliases.txt | 2 + + .../util/TimeZone/TimeZoneData/displaynames.txt | 2 - + jdk/test/sun/util/calendar/zi/TestZoneInfo310.java | 15 ++++-- + jdk/test/sun/util/calendar/zi/tzdata/VERSION | 2 +- + jdk/test/sun/util/calendar/zi/tzdata/asia | 30 +++++++---- + jdk/test/sun/util/calendar/zi/tzdata/backward | 2 + + jdk/test/sun/util/calendar/zi/tzdata/europe | 58 ++++------------------ + jdk/test/sun/util/calendar/zi/tzdata/southamerica | 10 +++- + jdk/test/sun/util/calendar/zi/tzdata/zone.tab | 2 - + 17 files changed, 99 insertions(+), 139 deletions(-) + +diff --git a/jdk/make/data/tzdata/VERSION b/jdk/make/data/tzdata/VERSION +index decb871..889d0e6 100644 +--- a/jdk/make/data/tzdata/VERSION ++++ b/jdk/make/data/tzdata/VERSION +@@ -21,4 +21,4 @@ + # or visit www.oracle.com if you need additional information or have any + # questions. + # +-tzdata2022c ++tzdata2022d +diff --git a/jdk/make/data/tzdata/asia b/jdk/make/data/tzdata/asia +index 6cb6d2c..1dc7d34 100644 +--- a/jdk/make/data/tzdata/asia ++++ b/jdk/make/data/tzdata/asia +@@ -3398,10 +3398,6 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 + # The winter time in 2015 started on October 23 at 01:00. + # https://wafa.ps/ar_page.aspx?id=CgpCdYa670694628582aCgpCdY + # http://www.palestinecabinet.gov.ps/portal/meeting/details/27583 +-# +-# From Paul Eggert (2019-04-10): +-# For now, guess spring-ahead transitions are at 00:00 on the Saturday +-# preceding March's last Sunday (i.e., Sat>=24). + + # From P Chan (2021-10-18): + # http://wafa.ps/Pages/Details/34701 +@@ -3418,6 +3414,18 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 + # From Heba Hamad (2022-03-10): + # summer time will begin in Palestine from Sunday 03-27-2022, 00:00 AM. + ++# From Heba Hamad (2022-08-30): ++# winter time will begin in Palestine from Saturday 10-29, 02:00 AM by ++# 60 minutes backwards. Also the state of Palestine adopted the summer ++# and winter time for the years: 2023,2024,2025,2026 ... ++# https://mm.icann.org/pipermail/tz/attachments/20220830/9f024566/Time-0001.pdf ++# (2022-08-31): ... the Saturday before the last Sunday in March and October ++# at 2:00 AM ,for the years from 2023 to 2026. ++# (2022-09-05): https://mtit.pna.ps/Site/New/1453 ++# ++# From Paul Eggert (2022-08-31): ++# For now, assume that this rule will also be used after 2026. ++ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule EgyptAsia 1957 only - May 10 0:00 1:00 S + Rule EgyptAsia 1957 1958 - Oct 1 0:00 0 - +@@ -3448,14 +3456,16 @@ Rule Palestine 2013 only - Sep 27 0:00 0 - + Rule Palestine 2014 only - Oct 24 0:00 0 - + Rule Palestine 2015 only - Mar 28 0:00 1:00 S + Rule Palestine 2015 only - Oct 23 1:00 0 - +-Rule Palestine 2016 2018 - Mar Sat>=24 1:00 1:00 S +-Rule Palestine 2016 2018 - Oct Sat>=24 1:00 0 - ++Rule Palestine 2016 2018 - Mar Sat<=30 1:00 1:00 S ++Rule Palestine 2016 2018 - Oct Sat<=30 1:00 0 - + Rule Palestine 2019 only - Mar 29 0:00 1:00 S +-Rule Palestine 2019 only - Oct Sat>=24 0:00 0 - +-Rule Palestine 2020 2021 - Mar Sat>=24 0:00 1:00 S ++Rule Palestine 2019 only - Oct Sat<=30 0:00 0 - ++Rule Palestine 2020 2021 - Mar Sat<=30 0:00 1:00 S + Rule Palestine 2020 only - Oct 24 1:00 0 - +-Rule Palestine 2021 max - Oct Fri>=23 1:00 0 - +-Rule Palestine 2022 max - Mar Sun>=25 0:00 1:00 S ++Rule Palestine 2021 only - Oct 29 1:00 0 - ++Rule Palestine 2022 only - Mar 27 0:00 1:00 S ++Rule Palestine 2022 max - Oct Sat<=30 2:00 0 - ++Rule Palestine 2023 max - Mar Sat<=30 2:00 1:00 S + + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Gaza 2:17:52 - LMT 1900 Oct +diff --git a/jdk/make/data/tzdata/backward b/jdk/make/data/tzdata/backward +index d4a29e8..7765d99 100644 +--- a/jdk/make/data/tzdata/backward ++++ b/jdk/make/data/tzdata/backward +@@ -113,6 +113,8 @@ Link Etc/UTC Etc/UCT + Link Europe/London Europe/Belfast + Link Europe/Kyiv Europe/Kiev + Link Europe/Chisinau Europe/Tiraspol ++Link Europe/Kyiv Europe/Uzhgorod ++Link Europe/Kyiv Europe/Zaporozhye + Link Europe/London GB + Link Europe/London GB-Eire + Link Etc/GMT GMT+0 +diff --git a/jdk/make/data/tzdata/europe b/jdk/make/data/tzdata/europe +index f7eb7a3..9e0a538 100644 +--- a/jdk/make/data/tzdata/europe ++++ b/jdk/make/data/tzdata/europe +@@ -2638,10 +2638,14 @@ Zone Europe/Simferopol 2:16:24 - LMT 1880 + # From Alexander Krivenyshev (2014-03-17): + # time change at 2:00 (2am) on March 30, 2014 + # https://vz.ru/news/2014/3/17/677464.html +-# From Paul Eggert (2014-03-30): +-# Simferopol and Sevastopol reportedly changed their central town clocks +-# late the previous day, but this appears to have been ceremonial +-# and the discrepancies are small enough to not worry about. ++# From Tim Parenti (2022-07-01), per Paul Eggert (2014-03-30): ++# The clocks at the railway station in Simferopol were put forward from 22:00 ++# to 24:00 the previous day in a "symbolic ceremony"; however, per ++# contemporaneous news reports, "ordinary Crimeans [made] the daylight savings ++# time switch at 2am" on Sunday. ++# https://www.business-standard.com/article/pti-stories/crimea-to-set-clocks-to-russia-time-114033000014_1.html ++# https://www.reuters.com/article/us-ukraine-crisis-crimea-time/crimea-switches-to-moscow-time-amid-incorporation-frenzy-idUKBREA2S0LT20140329 ++# https://www.bbc.com/news/av/world-europe-26806583 + 2:00 EU EE%sT 2014 Mar 30 2:00 + 4:00 - MSK 2014 Oct 26 2:00s + 3:00 - MSK +@@ -3774,8 +3778,8 @@ Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. + # US colleague David Cochrane) are still trying to get more + # information upon these local deviations from Kiev rules. + # +-# From Paul Eggert (2022-02-08): +-# For now, assume that Ukraine's other three zones followed the same rules, ++# From Paul Eggert (2022-08-27): ++# For now, assume that Ukraine's zones all followed the same rules, + # except that Crimea switched to Moscow time in 1994 as described elsewhere. + + # From Igor Karpov, who works for the Ukrainian Ministry of Justice, +@@ -3845,21 +3849,7 @@ Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. + # * Ukrainian Government's Resolution of 20.03.1992, No. 139. + # http://www.uazakon.com/documents/date_8u/pg_grcasa.htm + +-# From Paul Eggert (2022-04-12): +-# As is usual in tzdb, Ukrainian zones use the most common English spellings. +-# In particular, tzdb's name Europe/Kyiv uses the most common spelling in +-# English for Ukraine's capital. Although tzdb's former name was Europe/Kiev, +-# "Kyiv" is now more common due to widespread reporting of the current conflict. +-# Conversely, tzdb continues to use the names Europe/Uzhgorod and +-# Europe/Zaporozhye; this is similar to tzdb's use of Europe/Prague, which is +-# certainly wrong as a transliteration of the Czech "Praha". +-# English-language spelling of Ukrainian names is in flux, and +-# some day "Uzhhorod" or "Zaporizhzhia" may become substantially more +-# common in English; in the meantime, do not change these +-# English spellings as that means less disruption for our users. +- + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-# This represents most of Ukraine. See above for the spelling of "Kyiv". + Zone Europe/Kyiv 2:02:04 - LMT 1880 + 2:02:04 - KMT 1924 May 2 # Kyiv Mean Time + 2:00 - EET 1930 Jun 21 +@@ -3869,34 +3859,6 @@ Zone Europe/Kyiv 2:02:04 - LMT 1880 + 2:00 1:00 EEST 1991 Sep 29 3:00 + 2:00 C-Eur EE%sT 1996 May 13 + 2:00 EU EE%sT +-# Transcarpathia used CET 1990/1991. +-# "Uzhhorod" is the transliteration of the Rusyn/Ukrainian pronunciation, but +-# "Uzhgorod" is more common in English. +-Zone Europe/Uzhgorod 1:29:12 - LMT 1890 Oct +- 1:00 - CET 1940 +- 1:00 C-Eur CE%sT 1944 Oct +- 1:00 1:00 CEST 1944 Oct 26 +- 1:00 - CET 1945 Jun 29 +- 3:00 Russia MSK/MSD 1990 +- 3:00 - MSK 1990 Jul 1 2:00 +- 1:00 - CET 1991 Mar 31 3:00 +- 2:00 - EET 1992 Mar 20 +- 2:00 C-Eur EE%sT 1996 May 13 +- 2:00 EU EE%sT +-# Zaporozh'ye and eastern Lugansk oblasts observed DST 1990/1991. +-# "Zaporizhzhia" is the transliteration of the Ukrainian name, but +-# "Zaporozh'ye" is more common in English. Use the common English +-# spelling, except omit the apostrophe as it is not allowed in +-# portable Posix file names. +-Zone Europe/Zaporozhye 2:20:40 - LMT 1880 +- 2:20 - +0220 1924 May 2 +- 2:00 - EET 1930 Jun 21 +- 3:00 - MSK 1941 Aug 25 +- 1:00 C-Eur CE%sT 1943 Oct 25 +- 3:00 Russia MSK/MSD 1991 Mar 31 2:00 +- 2:00 E-Eur EE%sT 1992 Mar 20 +- 2:00 C-Eur EE%sT 1996 May 13 +- 2:00 EU EE%sT + + # Vatican City + # See Europe/Rome. +diff --git a/jdk/make/data/tzdata/southamerica b/jdk/make/data/tzdata/southamerica +index 13ec081..3c0e0e2 100644 +--- a/jdk/make/data/tzdata/southamerica ++++ b/jdk/make/data/tzdata/southamerica +@@ -1332,8 +1332,14 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914 + # for America/Santiago will start on midnight of September 11th; + # and will end on April 1st, 2023. Magallanes region (America/Punta_Arenas) + # will keep UTC -3 "indefinitely"... This is because on September 4th +-# we will have a voting whether to approve a new Constitution.... +-# https://www.interior.gob.cl/noticias/2022/08/09/comunicado-el-proximo-sabado-10-de-septiembre-los-relojes-se-deben-adelantar-una-hora/ ++# we will have a voting whether to approve a new Constitution. ++# ++# From Eduardo Romero Urra (2022-08-17): ++# https://www.diariooficial.interior.gob.cl/publicaciones/2022/08/13/43327/01/2172567.pdf ++# ++# From Paul Eggert (2022-08-17): ++# Although the presidential decree stops at fall 2026, assume that ++# similar DST rules will continue thereafter. + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Chile 1927 1931 - Sep 1 0:00 1:00 - +diff --git a/jdk/make/data/tzdata/zone.tab b/jdk/make/data/tzdata/zone.tab +index 51b65fa..ee02519 100644 +--- a/jdk/make/data/tzdata/zone.tab ++++ b/jdk/make/data/tzdata/zone.tab +@@ -424,8 +424,6 @@ TV -0831+17913 Pacific/Funafuti + TW +2503+12130 Asia/Taipei + TZ -0648+03917 Africa/Dar_es_Salaam + UA +5026+03031 Europe/Kyiv Ukraine (most areas) +-UA +4837+02218 Europe/Uzhgorod Transcarpathia +-UA +4750+03510 Europe/Zaporozhye Zaporozhye and east Lugansk + UG +0019+03225 Africa/Kampala + UM +2813-17722 Pacific/Midway Midway Islands + UM +1917+16637 Pacific/Wake Wake Island +diff --git a/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java b/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java +index 43bddd5..4b84cda 100644 +--- a/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java ++++ b/jdk/src/share/classes/sun/util/calendar/ZoneInfoFile.java +@@ -573,12 +573,8 @@ public final class ZoneInfoFile { + // we can then pass in the dom = -1, dow > 0 into ZoneInfo + // + // hacking, assume the >=24 is the result of ZRB optimization for +- // "last", it works for now. From tzdata2020d this hacking +- // will not work for Asia/Gaza and Asia/Hebron which follow +- // Palestine DST rules. +- if (dom < 0 || dom >= 24 && +- !(zoneId.equals("Asia/Gaza") || +- zoneId.equals("Asia/Hebron"))) { ++ // "last", it works for now. ++ if (dom < 0 || dom >= 24) { + params[1] = -1; + params[2] = toCalendarDOW[dow]; + } else { +@@ -600,7 +596,6 @@ public final class ZoneInfoFile { + params[7] = 0; + } else { + // hacking: see comment above +- // No need of hacking for Asia/Gaza and Asia/Hebron from tz2021e + if (dom < 0 || dom >= 24) { + params[6] = -1; + params[7] = toCalendarDOW[dow]; +diff --git a/jdk/test/java/util/TimeZone/TimeZoneData/VERSION b/jdk/test/java/util/TimeZone/TimeZoneData/VERSION +index c32bee3..7147016 100644 +--- a/jdk/test/java/util/TimeZone/TimeZoneData/VERSION ++++ b/jdk/test/java/util/TimeZone/TimeZoneData/VERSION +@@ -1 +1 @@ +-tzdata2022c ++tzdata2022d +diff --git a/jdk/test/java/util/TimeZone/TimeZoneData/aliases.txt b/jdk/test/java/util/TimeZone/TimeZoneData/aliases.txt +index a5e6428..e3ce742 100644 +--- a/jdk/test/java/util/TimeZone/TimeZoneData/aliases.txt ++++ b/jdk/test/java/util/TimeZone/TimeZoneData/aliases.txt +@@ -183,6 +183,8 @@ Link Etc/UTC Etc/UCT + Link Europe/London Europe/Belfast + Link Europe/Kyiv Europe/Kiev + Link Europe/Chisinau Europe/Tiraspol ++Link Europe/Kyiv Europe/Uzhgorod ++Link Europe/Kyiv Europe/Zaporozhye + Link Europe/London GB + Link Europe/London GB-Eire + Link Etc/GMT GMT+0 +diff --git a/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt b/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt +index fc14853..b382395 100644 +--- a/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt ++++ b/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt +@@ -163,11 +163,9 @@ Europe/Simferopol MSK + Europe/Sofia EET EEST + Europe/Tallinn EET EEST + Europe/Tirane CET CEST +-Europe/Uzhgorod EET EEST + Europe/Vienna CET CEST + Europe/Vilnius EET EEST + Europe/Warsaw CET CEST +-Europe/Zaporozhye EET EEST + Europe/Zurich CET CEST + HST HST + MET MET MEST +diff --git a/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java +index 3aad69f..c682531 100644 +--- a/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java ++++ b/jdk/test/sun/util/calendar/zi/TestZoneInfo310.java +@@ -173,10 +173,19 @@ public class TestZoneInfo310 { + * Temporary ignoring the failing TimeZones which are having zone + * rules defined till year 2037 and/or above and have negative DST + * save time in IANA tzdata. This bug is tracked via JDK-8223388. ++ * ++ * Tehran/Iran rule has rules beyond 2037, in which javazic assumes ++ * to be the last year. Thus javazic's rule is based on year 2037 ++ * (Mar 20th/Sep 20th are the cutover dates), while the real rule ++ * has year 2087 where Mar 21st/Sep 21st are the cutover dates. + */ +- if (zid.equals("Africa/Casablanca") || zid.equals("Africa/El_Aaiun") +- || zid.equals("Asia/Tehran") || zid.equals("Iran")) { +- continue; ++ if (zid.equals("Africa/Casablanca") || // uses "Morocco" rule ++ zid.equals("Africa/El_Aaiun") || // uses "Morocco" rule ++ zid.equals("Asia/Tehran") || // last rule mismatch ++ zid.equals("Asia/Gaza") || // uses "Palestine" rule ++ zid.equals("Asia/Hebron") || // uses "Palestine" rule ++ zid.equals("Iran")) { // last rule mismatch ++ continue; + } + if (! zi.equalsTo(ziOLD)) { + System.out.println(zi.diffsTo(ziOLD)); +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/VERSION b/jdk/test/sun/util/calendar/zi/tzdata/VERSION +index decb871..889d0e6 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/VERSION ++++ b/jdk/test/sun/util/calendar/zi/tzdata/VERSION +@@ -21,4 +21,4 @@ + # or visit www.oracle.com if you need additional information or have any + # questions. + # +-tzdata2022c ++tzdata2022d +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/asia b/jdk/test/sun/util/calendar/zi/tzdata/asia +index 6cb6d2c..1dc7d34 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/asia ++++ b/jdk/test/sun/util/calendar/zi/tzdata/asia +@@ -3398,10 +3398,6 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 + # The winter time in 2015 started on October 23 at 01:00. + # https://wafa.ps/ar_page.aspx?id=CgpCdYa670694628582aCgpCdY + # http://www.palestinecabinet.gov.ps/portal/meeting/details/27583 +-# +-# From Paul Eggert (2019-04-10): +-# For now, guess spring-ahead transitions are at 00:00 on the Saturday +-# preceding March's last Sunday (i.e., Sat>=24). + + # From P Chan (2021-10-18): + # http://wafa.ps/Pages/Details/34701 +@@ -3418,6 +3414,18 @@ Zone Asia/Karachi 4:28:12 - LMT 1907 + # From Heba Hamad (2022-03-10): + # summer time will begin in Palestine from Sunday 03-27-2022, 00:00 AM. + ++# From Heba Hamad (2022-08-30): ++# winter time will begin in Palestine from Saturday 10-29, 02:00 AM by ++# 60 minutes backwards. Also the state of Palestine adopted the summer ++# and winter time for the years: 2023,2024,2025,2026 ... ++# https://mm.icann.org/pipermail/tz/attachments/20220830/9f024566/Time-0001.pdf ++# (2022-08-31): ... the Saturday before the last Sunday in March and October ++# at 2:00 AM ,for the years from 2023 to 2026. ++# (2022-09-05): https://mtit.pna.ps/Site/New/1453 ++# ++# From Paul Eggert (2022-08-31): ++# For now, assume that this rule will also be used after 2026. ++ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule EgyptAsia 1957 only - May 10 0:00 1:00 S + Rule EgyptAsia 1957 1958 - Oct 1 0:00 0 - +@@ -3448,14 +3456,16 @@ Rule Palestine 2013 only - Sep 27 0:00 0 - + Rule Palestine 2014 only - Oct 24 0:00 0 - + Rule Palestine 2015 only - Mar 28 0:00 1:00 S + Rule Palestine 2015 only - Oct 23 1:00 0 - +-Rule Palestine 2016 2018 - Mar Sat>=24 1:00 1:00 S +-Rule Palestine 2016 2018 - Oct Sat>=24 1:00 0 - ++Rule Palestine 2016 2018 - Mar Sat<=30 1:00 1:00 S ++Rule Palestine 2016 2018 - Oct Sat<=30 1:00 0 - + Rule Palestine 2019 only - Mar 29 0:00 1:00 S +-Rule Palestine 2019 only - Oct Sat>=24 0:00 0 - +-Rule Palestine 2020 2021 - Mar Sat>=24 0:00 1:00 S ++Rule Palestine 2019 only - Oct Sat<=30 0:00 0 - ++Rule Palestine 2020 2021 - Mar Sat<=30 0:00 1:00 S + Rule Palestine 2020 only - Oct 24 1:00 0 - +-Rule Palestine 2021 max - Oct Fri>=23 1:00 0 - +-Rule Palestine 2022 max - Mar Sun>=25 0:00 1:00 S ++Rule Palestine 2021 only - Oct 29 1:00 0 - ++Rule Palestine 2022 only - Mar 27 0:00 1:00 S ++Rule Palestine 2022 max - Oct Sat<=30 2:00 0 - ++Rule Palestine 2023 max - Mar Sat<=30 2:00 1:00 S + + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Gaza 2:17:52 - LMT 1900 Oct +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/backward b/jdk/test/sun/util/calendar/zi/tzdata/backward +index d4a29e8..7765d99 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/backward ++++ b/jdk/test/sun/util/calendar/zi/tzdata/backward +@@ -113,6 +113,8 @@ Link Etc/UTC Etc/UCT + Link Europe/London Europe/Belfast + Link Europe/Kyiv Europe/Kiev + Link Europe/Chisinau Europe/Tiraspol ++Link Europe/Kyiv Europe/Uzhgorod ++Link Europe/Kyiv Europe/Zaporozhye + Link Europe/London GB + Link Europe/London GB-Eire + Link Etc/GMT GMT+0 +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/europe b/jdk/test/sun/util/calendar/zi/tzdata/europe +index f7eb7a3..9e0a538 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/europe ++++ b/jdk/test/sun/util/calendar/zi/tzdata/europe +@@ -2638,10 +2638,14 @@ Zone Europe/Simferopol 2:16:24 - LMT 1880 + # From Alexander Krivenyshev (2014-03-17): + # time change at 2:00 (2am) on March 30, 2014 + # https://vz.ru/news/2014/3/17/677464.html +-# From Paul Eggert (2014-03-30): +-# Simferopol and Sevastopol reportedly changed their central town clocks +-# late the previous day, but this appears to have been ceremonial +-# and the discrepancies are small enough to not worry about. ++# From Tim Parenti (2022-07-01), per Paul Eggert (2014-03-30): ++# The clocks at the railway station in Simferopol were put forward from 22:00 ++# to 24:00 the previous day in a "symbolic ceremony"; however, per ++# contemporaneous news reports, "ordinary Crimeans [made] the daylight savings ++# time switch at 2am" on Sunday. ++# https://www.business-standard.com/article/pti-stories/crimea-to-set-clocks-to-russia-time-114033000014_1.html ++# https://www.reuters.com/article/us-ukraine-crisis-crimea-time/crimea-switches-to-moscow-time-amid-incorporation-frenzy-idUKBREA2S0LT20140329 ++# https://www.bbc.com/news/av/world-europe-26806583 + 2:00 EU EE%sT 2014 Mar 30 2:00 + 4:00 - MSK 2014 Oct 26 2:00s + 3:00 - MSK +@@ -3774,8 +3778,8 @@ Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. + # US colleague David Cochrane) are still trying to get more + # information upon these local deviations from Kiev rules. + # +-# From Paul Eggert (2022-02-08): +-# For now, assume that Ukraine's other three zones followed the same rules, ++# From Paul Eggert (2022-08-27): ++# For now, assume that Ukraine's zones all followed the same rules, + # except that Crimea switched to Moscow time in 1994 as described elsewhere. + + # From Igor Karpov, who works for the Ukrainian Ministry of Justice, +@@ -3845,21 +3849,7 @@ Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. + # * Ukrainian Government's Resolution of 20.03.1992, No. 139. + # http://www.uazakon.com/documents/date_8u/pg_grcasa.htm + +-# From Paul Eggert (2022-04-12): +-# As is usual in tzdb, Ukrainian zones use the most common English spellings. +-# In particular, tzdb's name Europe/Kyiv uses the most common spelling in +-# English for Ukraine's capital. Although tzdb's former name was Europe/Kiev, +-# "Kyiv" is now more common due to widespread reporting of the current conflict. +-# Conversely, tzdb continues to use the names Europe/Uzhgorod and +-# Europe/Zaporozhye; this is similar to tzdb's use of Europe/Prague, which is +-# certainly wrong as a transliteration of the Czech "Praha". +-# English-language spelling of Ukrainian names is in flux, and +-# some day "Uzhhorod" or "Zaporizhzhia" may become substantially more +-# common in English; in the meantime, do not change these +-# English spellings as that means less disruption for our users. +- + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-# This represents most of Ukraine. See above for the spelling of "Kyiv". + Zone Europe/Kyiv 2:02:04 - LMT 1880 + 2:02:04 - KMT 1924 May 2 # Kyiv Mean Time + 2:00 - EET 1930 Jun 21 +@@ -3869,34 +3859,6 @@ Zone Europe/Kyiv 2:02:04 - LMT 1880 + 2:00 1:00 EEST 1991 Sep 29 3:00 + 2:00 C-Eur EE%sT 1996 May 13 + 2:00 EU EE%sT +-# Transcarpathia used CET 1990/1991. +-# "Uzhhorod" is the transliteration of the Rusyn/Ukrainian pronunciation, but +-# "Uzhgorod" is more common in English. +-Zone Europe/Uzhgorod 1:29:12 - LMT 1890 Oct +- 1:00 - CET 1940 +- 1:00 C-Eur CE%sT 1944 Oct +- 1:00 1:00 CEST 1944 Oct 26 +- 1:00 - CET 1945 Jun 29 +- 3:00 Russia MSK/MSD 1990 +- 3:00 - MSK 1990 Jul 1 2:00 +- 1:00 - CET 1991 Mar 31 3:00 +- 2:00 - EET 1992 Mar 20 +- 2:00 C-Eur EE%sT 1996 May 13 +- 2:00 EU EE%sT +-# Zaporozh'ye and eastern Lugansk oblasts observed DST 1990/1991. +-# "Zaporizhzhia" is the transliteration of the Ukrainian name, but +-# "Zaporozh'ye" is more common in English. Use the common English +-# spelling, except omit the apostrophe as it is not allowed in +-# portable Posix file names. +-Zone Europe/Zaporozhye 2:20:40 - LMT 1880 +- 2:20 - +0220 1924 May 2 +- 2:00 - EET 1930 Jun 21 +- 3:00 - MSK 1941 Aug 25 +- 1:00 C-Eur CE%sT 1943 Oct 25 +- 3:00 Russia MSK/MSD 1991 Mar 31 2:00 +- 2:00 E-Eur EE%sT 1992 Mar 20 +- 2:00 C-Eur EE%sT 1996 May 13 +- 2:00 EU EE%sT + + # Vatican City + # See Europe/Rome. +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/southamerica b/jdk/test/sun/util/calendar/zi/tzdata/southamerica +index 13ec081..3c0e0e2 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/southamerica ++++ b/jdk/test/sun/util/calendar/zi/tzdata/southamerica +@@ -1332,8 +1332,14 @@ Zone America/Rio_Branco -4:31:12 - LMT 1914 + # for America/Santiago will start on midnight of September 11th; + # and will end on April 1st, 2023. Magallanes region (America/Punta_Arenas) + # will keep UTC -3 "indefinitely"... This is because on September 4th +-# we will have a voting whether to approve a new Constitution.... +-# https://www.interior.gob.cl/noticias/2022/08/09/comunicado-el-proximo-sabado-10-de-septiembre-los-relojes-se-deben-adelantar-una-hora/ ++# we will have a voting whether to approve a new Constitution. ++# ++# From Eduardo Romero Urra (2022-08-17): ++# https://www.diariooficial.interior.gob.cl/publicaciones/2022/08/13/43327/01/2172567.pdf ++# ++# From Paul Eggert (2022-08-17): ++# Although the presidential decree stops at fall 2026, assume that ++# similar DST rules will continue thereafter. + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Chile 1927 1931 - Sep 1 0:00 1:00 - +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/zone.tab b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab +index 51b65fa..ee02519 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/zone.tab ++++ b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab +@@ -424,8 +424,6 @@ TV -0831+17913 Pacific/Funafuti + TW +2503+12130 Asia/Taipei + TZ -0648+03917 Africa/Dar_es_Salaam + UA +5026+03031 Europe/Kyiv Ukraine (most areas) +-UA +4837+02218 Europe/Uzhgorod Transcarpathia +-UA +4750+03510 Europe/Zaporozhye Zaporozhye and east Lugansk + UG +0019+03225 Africa/Kampala + UM +2813-17722 Pacific/Midway Midway Islands + UM +1917+16637 Pacific/Wake Wake Island +-- +1.8.3.1 diff --git a/8296108-tz-Update-Timezone-Data-to-2022f.patch b/8296108-tz-Update-Timezone-Data-to-2022f.patch new file mode 100644 index 0000000..19b7fbb --- /dev/null +++ b/8296108-tz-Update-Timezone-Data-to-2022f.patch @@ -0,0 +1,4516 @@ +From b8733a1abad2eb73a9a1ae5e74be047cf7c5866a Mon Sep 17 00:00:00 2001 +From: eapen +Date: Wed, 30 Nov 2022 15:47:49 +0800 +Subject: [PATCH 09/33] I68TO2: 8296108: (tz) Update Timezone Data to 2022f +--- + jdk/make/data/tzdata/VERSION | 2 +- + jdk/make/data/tzdata/africa | 213 ++++--------- + jdk/make/data/tzdata/antarctica | 2 +- + jdk/make/data/tzdata/asia | 69 ++--- + jdk/make/data/tzdata/australasia | 58 ++-- + jdk/make/data/tzdata/backward | 291 ++++++++++++++---- + jdk/make/data/tzdata/etcetera | 17 +- + jdk/make/data/tzdata/europe | 202 +++++------- + jdk/make/data/tzdata/northamerica | 171 +++-------- + jdk/make/data/tzdata/southamerica | 15 - + jdk/make/data/tzdata/zone.tab | 3 - + .../classes/sun/util/resources/TimeZoneNames.java | 6 +- + .../sun/util/resources/de/TimeZoneNames_de.java | 6 +- + .../sun/util/resources/es/TimeZoneNames_es.java | 6 +- + .../sun/util/resources/fr/TimeZoneNames_fr.java | 6 +- + .../sun/util/resources/it/TimeZoneNames_it.java | 6 +- + .../sun/util/resources/ja/TimeZoneNames_ja.java | 6 +- + .../sun/util/resources/ko/TimeZoneNames_ko.java | 6 +- + .../sun/util/resources/pt/TimeZoneNames_pt_BR.java | 6 +- + .../sun/util/resources/sv/TimeZoneNames_sv.java | 6 +- + .../sun/util/resources/zh/TimeZoneNames_zh_CN.java | 6 +- + .../sun/util/resources/zh/TimeZoneNames_zh_TW.java | 6 +- + jdk/test/java/util/TimeZone/TimeZoneData/VERSION | 2 +- + .../java/util/TimeZone/TimeZoneData/aliases.txt | 341 +++++++++++---------- + .../util/TimeZone/TimeZoneData/displaynames.txt | 7 +- + jdk/test/sun/util/calendar/zi/tzdata/VERSION | 2 +- + jdk/test/sun/util/calendar/zi/tzdata/africa | 213 ++++--------- + jdk/test/sun/util/calendar/zi/tzdata/antarctica | 2 +- + jdk/test/sun/util/calendar/zi/tzdata/asia | 69 ++--- + jdk/test/sun/util/calendar/zi/tzdata/australasia | 58 ++-- + jdk/test/sun/util/calendar/zi/tzdata/backward | 291 ++++++++++++++---- + jdk/test/sun/util/calendar/zi/tzdata/etcetera | 17 +- + jdk/test/sun/util/calendar/zi/tzdata/europe | 202 +++++------- + jdk/test/sun/util/calendar/zi/tzdata/northamerica | 171 +++-------- + jdk/test/sun/util/calendar/zi/tzdata/southamerica | 15 - + jdk/test/sun/util/calendar/zi/tzdata/zone.tab | 3 - + 36 files changed, 1103 insertions(+), 1399 deletions(-) + +diff --git a/jdk/make/data/tzdata/VERSION b/jdk/make/data/tzdata/VERSION +index b8cb36e..b8d9ae7 100644 +--- a/jdk/make/data/tzdata/VERSION ++++ b/jdk/make/data/tzdata/VERSION +@@ -21,4 +21,4 @@ + # or visit www.oracle.com if you need additional information or have any + # questions. + # +-tzdata2022e ++tzdata2022f +diff --git a/jdk/make/data/tzdata/africa b/jdk/make/data/tzdata/africa +index e13899b..b4559cd 100644 +--- a/jdk/make/data/tzdata/africa ++++ b/jdk/make/data/tzdata/africa +@@ -120,22 +120,6 @@ Zone Africa/Algiers 0:12:12 - LMT 1891 Mar 16 + 0:00 Algeria WE%sT 1981 May + 1:00 - CET + +-# Angola +-# Benin +-# See Africa/Lagos. +- +-# Botswana +-# See Africa/Maputo. +- +-# Burkina Faso +-# See Africa/Abidjan. +- +-# Burundi +-# See Africa/Maputo. +- +-# Cameroon +-# See Africa/Lagos. +- + # Cape Verde / Cabo Verde + # + # From Paul Eggert (2018-02-16): +@@ -150,9 +134,6 @@ Zone Atlantic/Cape_Verde -1:34:04 - LMT 1912 Jan 01 2:00u # Praia + -2:00 - -02 1975 Nov 25 2:00 + -1:00 - -01 + +-# Central African Republic +-# See Africa/Lagos. +- + # Chad + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Africa/Ndjamena 1:00:12 - LMT 1912 # N'Djamena +@@ -160,33 +141,29 @@ Zone Africa/Ndjamena 1:00:12 - LMT 1912 # N'Djamena + 1:00 1:00 WAST 1980 Mar 8 + 1:00 - WAT + +-# Comoros +-# See Africa/Nairobi. +- +-# Democratic Republic of the Congo +-# See Africa/Lagos for the western part and Africa/Maputo for the eastern. ++# Burkina Faso ++# Côte d'Ivoire (Ivory Coast) ++# The Gambia ++# Ghana ++# Guinea ++# Iceland ++# Mali ++# Mauritania ++# St Helena ++# Senegal ++# Sierra Leone ++# Togo + +-# Republic of the Congo +-# See Africa/Lagos. ++# The other parts of the St Helena territory are similar: ++# Tristan da Cunha: on GMT, say Whitman and the CIA ++# Ascension: on GMT, say the USNO (1995-12-21) and the CIA ++# Gough (scientific station since 1955; sealers wintered previously): ++# on GMT, says the CIA ++# Inaccessible, Nightingale: uninhabited + +-# Côte d'Ivoire / Ivory Coast + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Africa/Abidjan -0:16:08 - LMT 1912 + 0:00 - GMT +-Link Africa/Abidjan Africa/Accra # Ghana +-Link Africa/Abidjan Africa/Bamako # Mali +-Link Africa/Abidjan Africa/Banjul # The Gambia +-Link Africa/Abidjan Africa/Conakry # Guinea +-Link Africa/Abidjan Africa/Dakar # Senegal +-Link Africa/Abidjan Africa/Freetown # Sierra Leone +-Link Africa/Abidjan Africa/Lome # Togo +-Link Africa/Abidjan Africa/Nouakchott # Mauritania +-Link Africa/Abidjan Africa/Ouagadougou # Burkina Faso +-Link Africa/Abidjan Atlantic/Reykjavik # Iceland +-Link Africa/Abidjan Atlantic/St_Helena # St Helena +- +-# Djibouti +-# See Africa/Nairobi. + + ############################################################################### + +@@ -382,33 +359,6 @@ Rule Egypt 2014 only - Sep lastThu 24:00 0 - + Zone Africa/Cairo 2:05:09 - LMT 1900 Oct + 2:00 Egypt EE%sT + +-# Equatorial Guinea +-# See Africa/Lagos. +- +-# Eritrea +-# See Africa/Nairobi. +- +-# Eswatini (formerly Swaziland) +-# See Africa/Johannesburg. +- +-# Ethiopia +-# See Africa/Nairobi. +-# +-# Unfortunately tzdb records only Western clock time in use in Ethiopia, +-# as the tzdb format is not up to properly recording a common Ethiopian +-# timekeeping practice that is based on solar time. See: +-# Mortada D. If you have a meeting in Ethiopia, you'd better double +-# check the time. PRI's The World. 2015-01-30 15:15 -05. +-# https://www.pri.org/stories/2015-01-30/if-you-have-meeting-ethiopia-you-better-double-check-time +- +-# Gabon +-# See Africa/Lagos. +- +-# The Gambia +-# Ghana +-# Guinea +-# See Africa/Abidjan. +- + # Guinea-Bissau + # + # From Paul Eggert (2018-02-16): +@@ -421,7 +371,16 @@ Zone Africa/Bissau -1:02:20 - LMT 1912 Jan 1 1:00u + -1:00 - -01 1975 + 0:00 - GMT + ++# Comoros ++# Djibouti ++# Eritrea ++# Ethiopia + # Kenya ++# Madagascar ++# Mayotte ++# Somalia ++# Tanzania ++# Uganda + + # From P Chan (2020-10-24): + # +@@ -464,6 +423,14 @@ Zone Africa/Bissau -1:02:20 - LMT 1912 Jan 1 1:00u + # The 1908-05-01 announcement does not give an effective date, + # so just say "1908 May". + ++# From Paul Eggert (2018-09-11): ++# Unfortunately tzdb records only Western clock time in use in Ethiopia, ++# as the tzdb format is not up to properly recording a common Ethiopian ++# timekeeping practice that is based on solar time. See: ++# Mortada D. If you have a meeting in Ethiopia, you'd better double ++# check the time. PRI's The World. 2015-01-30 15:15 -05. ++# https://www.pri.org/stories/2015-01-30/if-you-have-meeting-ethiopia-you-better-double-check-time ++ + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Africa/Nairobi 2:27:16 - LMT 1908 May + 2:30 - +0230 1928 Jun 30 24:00 +@@ -471,18 +438,6 @@ Zone Africa/Nairobi 2:27:16 - LMT 1908 May + 2:30 - +0230 1936 Dec 31 24:00 + 2:45 - +0245 1942 Jul 31 24:00 + 3:00 - EAT +-Link Africa/Nairobi Africa/Addis_Ababa # Ethiopia +-Link Africa/Nairobi Africa/Asmara # Eritrea +-Link Africa/Nairobi Africa/Dar_es_Salaam # Tanzania +-Link Africa/Nairobi Africa/Djibouti +-Link Africa/Nairobi Africa/Kampala # Uganda +-Link Africa/Nairobi Africa/Mogadishu # Somalia +-Link Africa/Nairobi Indian/Antananarivo # Madagascar +-Link Africa/Nairobi Indian/Comoro +-Link Africa/Nairobi Indian/Mayotte +- +-# Lesotho +-# See Africa/Johannesburg. + + # Liberia + # +@@ -563,16 +518,6 @@ Zone Africa/Tripoli 0:52:44 - LMT 1920 + 1:00 Libya CE%sT 2013 Oct 25 2:00 + 2:00 - EET + +-# Madagascar +-# See Africa/Nairobi. +- +-# Malawi +-# See Africa/Maputo. +- +-# Mali +-# Mauritania +-# See Africa/Abidjan. +- + # Mauritius + + # From Steffen Thorsen (2008-06-25): +@@ -666,12 +611,6 @@ Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis + # Agalega Is, Rodriguez + # no information; probably like Indian/Mauritius + +-# Mayotte +-# See Africa/Nairobi. +- +-# Morocco +-# See Africa/Ceuta for Spanish Morocco. +- + # From Alex Krivenyshev (2008-05-09): + # Here is an article that Morocco plan to introduce Daylight Saving Time between + # 1 June, 2008 and 27 September, 2008. +@@ -1160,7 +1099,14 @@ Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún + 0:00 Morocco +00/+01 2018 Oct 28 3:00 + 0:00 Morocco +00/+01 + ++# Botswana ++# Burundi ++# Democratic Republic of the Congo (eastern) ++# Malawi + # Mozambique ++# Rwanda ++# Zambia ++# Zimbabwe + # + # Shanks gives 1903-03-01 for the transition to CAT. + # Perhaps the 1911-05-26 Portuguese decree +@@ -1170,14 +1116,6 @@ Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Africa/Maputo 2:10:20 - LMT 1903 Mar + 2:00 - CAT +-Link Africa/Maputo Africa/Blantyre # Malawi +-Link Africa/Maputo Africa/Bujumbura # Burundi +-Link Africa/Maputo Africa/Gaborone # Botswana +-Link Africa/Maputo Africa/Harare # Zimbabwe +-Link Africa/Maputo Africa/Kigali # Rwanda +-Link Africa/Maputo Africa/Lubumbashi # E Dem. Rep. of Congo +-Link Africa/Maputo Africa/Lusaka # Zambia +- + + # Namibia + +@@ -1256,9 +1194,16 @@ Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8 + 2:00 - CAT + # End of rearguard section. + +-# Niger +-# See Africa/Lagos. + ++# Angola ++# Benin ++# Cameroon ++# Central African Republic ++# Democratic Republic of the Congo (western) ++# Republic of the Congo ++# Equatorial Guinea ++# Gabon ++# Niger + # Nigeria + + # From P Chan (2020-12-03): +@@ -1324,32 +1269,6 @@ Zone Africa/Lagos 0:13:35 - LMT 1905 Jul 1 + 0:13:35 - LMT 1914 Jan 1 + 0:30 - +0030 1919 Sep 1 + 1:00 - WAT +-Link Africa/Lagos Africa/Bangui # Central African Republic +-Link Africa/Lagos Africa/Brazzaville # Rep. of the Congo +-Link Africa/Lagos Africa/Douala # Cameroon +-Link Africa/Lagos Africa/Kinshasa # Dem. Rep. of the Congo (west) +-Link Africa/Lagos Africa/Libreville # Gabon +-Link Africa/Lagos Africa/Luanda # Angola +-Link Africa/Lagos Africa/Malabo # Equatorial Guinea +-Link Africa/Lagos Africa/Niamey # Niger +-Link Africa/Lagos Africa/Porto-Novo # Benin +- +-# Réunion +-# See Asia/Dubai. +-# +-# The Crozet Islands also observe Réunion time; see the 'antarctica' file. +- +-# Rwanda +-# See Africa/Maputo. +- +-# St Helena +-# See Africa/Abidjan. +-# The other parts of the St Helena territory are similar: +-# Tristan da Cunha: on GMT, say Whitman and the CIA +-# Ascension: on GMT, say the USNO (1995-12-21) and the CIA +-# Gough (scientific station since 1955; sealers wintered previously): +-# on GMT, says the CIA +-# Inaccessible, Nightingale: uninhabited + + # São Tomé and Príncipe + +@@ -1378,19 +1297,10 @@ Zone Africa/Sao_Tome 0:26:56 - LMT 1884 + 1:00 - WAT 2019 Jan 1 02:00 + 0:00 - GMT + +-# Senegal +-# See Africa/Abidjan. +- +-# Seychelles +-# See Asia/Dubai. +- +-# Sierra Leone +-# See Africa/Abidjan. +- +-# Somalia +-# See Africa/Nairobi. +- ++# Eswatini (Swaziland) ++# Lesotho + # South Africa ++ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule SA 1942 1943 - Sep Sun>=15 2:00 1:00 - + Rule SA 1943 1944 - Mar Sun>=15 2:00 0 - +@@ -1398,8 +1308,6 @@ Rule SA 1943 1944 - Mar Sun>=15 2:00 0 - + Zone Africa/Johannesburg 1:52:00 - LMT 1892 Feb 8 + 1:30 - SAST 1903 Mar + 2:00 SA SAST +-Link Africa/Johannesburg Africa/Maseru # Lesotho +-Link Africa/Johannesburg Africa/Mbabane # Eswatini + # + # Marion and Prince Edward Is + # scientific station since 1947 +@@ -1448,12 +1356,6 @@ Zone Africa/Juba 2:06:28 - LMT 1931 + 3:00 - EAT 2021 Feb 1 00:00 + 2:00 - CAT + +-# Tanzania +-# See Africa/Nairobi. +- +-# Togo +-# See Africa/Abidjan. +- + # Tunisia + + # From Gwillim Law (2005-04-30): +@@ -1551,10 +1453,3 @@ Rule Tunisia 2006 2008 - Oct lastSun 2:00s 0 - + Zone Africa/Tunis 0:40:44 - LMT 1881 May 12 + 0:09:21 - PMT 1911 Mar 11 # Paris Mean Time + 1:00 Tunisia CE%sT +- +-# Uganda +-# See Africa/Nairobi. +- +-# Zambia +-# Zimbabwe +-# See Africa/Maputo. +diff --git a/jdk/make/data/tzdata/antarctica b/jdk/make/data/tzdata/antarctica +index 34c302e..792542b 100644 +--- a/jdk/make/data/tzdata/antarctica ++++ b/jdk/make/data/tzdata/antarctica +@@ -329,4 +329,4 @@ Zone Antarctica/Rothera 0 - -00 1976 Dec 1 + # we have to go around and set them back 5 minutes or so. + # Maybe if we let them run fast all of the time, we'd get to leave here sooner!! + # +-# See 'australasia' for Antarctica/McMurdo. ++# See Pacific/Auckland. +diff --git a/jdk/make/data/tzdata/asia b/jdk/make/data/tzdata/asia +index f1771e4..8f1fcac 100644 +--- a/jdk/make/data/tzdata/asia ++++ b/jdk/make/data/tzdata/asia +@@ -172,9 +172,6 @@ Zone Asia/Baku 3:19:24 - LMT 1924 May 2 + 4:00 EUAsia +04/+05 1997 + 4:00 Azer +04/+05 + +-# Bahrain +-# See Asia/Qatar. +- + # Bangladesh + # From Alexander Krivenyshev (2009-05-13): + # According to newspaper Asian Tribune (May 6, 2009) Bangladesh may introduce +@@ -277,10 +274,8 @@ Zone Indian/Chagos 4:49:40 - LMT 1907 + 5:00 - +05 1996 + 6:00 - +06 + +-# Brunei +-# See Asia/Kuching. +- +-# Burma / Myanmar ++# Cocos (Keeling) Islands ++# Myanmar (Burma) + + # Milne says 6:24:40 was the meridian of the time ball observatory at Rangoon. + +@@ -296,11 +291,6 @@ Zone Asia/Yangon 6:24:47 - LMT 1880 # or Rangoon + 6:30 - +0630 1942 May + 9:00 - +09 1945 May 3 + 6:30 - +0630 +-Link Asia/Yangon Indian/Cocos +- +-# Cambodia +-# See Asia/Bangkok. +- + + # China + +@@ -688,10 +678,9 @@ Zone Asia/Shanghai 8:05:43 - LMT 1901 + 8:00 PRC C%sT + # Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi + # / Wulumuqi. (Please use Asia/Shanghai if you prefer Beijing time.) ++# Vostok base in Antarctica matches this since 1970. + Zone Asia/Urumqi 5:50:20 - LMT 1928 + 6:00 - +06 +-Link Asia/Urumqi Antarctica/Vostok +- + + # Hong Kong + +@@ -1195,10 +1184,6 @@ Zone Asia/Famagusta 2:15:48 - LMT 1921 Nov 14 + 3:00 - +03 2017 Oct 29 1:00u + 2:00 EUAsia EE%sT + +-# Classically, Cyprus belongs to Asia; e.g. see Herodotus, Histories, I.72. +-# However, for various reasons many users expect to find it under Europe. +-Link Asia/Nicosia Europe/Nicosia +- + # Georgia + # From Paul Eggert (1994-11-19): + # Today's _Economist_ (p 60) reports that Georgia moved its clocks forward +@@ -2727,14 +2712,6 @@ Zone Asia/Pyongyang 8:23:00 - LMT 1908 Apr 1 + 8:30 - KST 2018 May 4 23:30 + 9:00 - KST + +-############################################################################### +- +-# Kuwait +-# See Asia/Riyadh. +- +-# Laos +-# See Asia/Bangkok. +- + + # Lebanon + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S +@@ -2766,7 +2743,9 @@ Rule Lebanon 1999 max - Oct lastSun 0:00 0 - + Zone Asia/Beirut 2:22:00 - LMT 1880 + 2:00 Lebanon EE%sT + +-# Malaysia ++# Brunei ++# Malaysia (eastern) ++# + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule NBorneo 1935 1941 - Sep 14 0:00 0:20 - + Rule NBorneo 1935 1941 - Dec 14 0:00 0 - +@@ -2783,14 +2762,12 @@ Zone Asia/Kuching 7:21:20 - LMT 1926 Mar + 8:00 NBorneo +08/+0820 1942 Feb 16 + 9:00 - +09 1945 Sep 12 + 8:00 - +08 +-Link Asia/Kuching Asia/Brunei + + # Maldives + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Indian/Maldives 4:54:00 - LMT 1880 # Malé + 4:54:00 - MMT 1960 # Malé Mean Time + 5:00 - +05 +-Link Indian/Maldives Indian/Kerguelen + + # Mongolia + +@@ -2953,9 +2930,6 @@ Zone Asia/Kathmandu 5:41:16 - LMT 1920 + 5:30 - +0530 1986 + 5:45 - +0545 + +-# Oman +-# See Asia/Dubai. +- + # Pakistan + + # From Rives McDow (2002-03-13): +@@ -3566,14 +3540,18 @@ Zone Asia/Manila -15:56:00 - LMT 1844 Dec 31 + 9:00 - JST 1944 Nov + 8:00 Phil P%sT + ++# Bahrain + # Qatar + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Qatar 3:26:08 - LMT 1920 # Al Dawhah / Doha + 4:00 - +04 1972 Jun + 3:00 - +03 +-Link Asia/Qatar Asia/Bahrain + ++# Kuwait + # Saudi Arabia ++# Yemen ++# ++# Japan's year-round bases in Antarctica match this since 1970. + # + # From Paul Eggert (2018-08-29): + # Time in Saudi Arabia and other countries in the Arabian peninsula was not +@@ -3618,9 +3596,6 @@ Link Asia/Qatar Asia/Bahrain + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Riyadh 3:06:52 - LMT 1947 Mar 14 + 3:00 - +03 +-Link Asia/Riyadh Antarctica/Syowa +-Link Asia/Riyadh Asia/Aden # Yemen +-Link Asia/Riyadh Asia/Kuwait + + # Singapore + # taken from Mok Ly Yng (2003-10-30) +@@ -3635,7 +3610,6 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 + 9:00 - +09 1945 Sep 12 + 7:30 - +0730 1982 Jan 1 + 8:00 - +08 +-Link Asia/Singapore Asia/Kuala_Lumpur + + # Spratly Is + # no information +@@ -3881,14 +3855,15 @@ Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2 + 5:00 1:00 +06 1991 Sep 9 2:00s + 5:00 - +05 + ++# Cambodia ++# Christmas I ++# Laos + # Thailand ++# Vietnam (northern) + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Bangkok 6:42:04 - LMT 1880 + 6:42:04 - BMT 1920 Apr # Bangkok Mean Time + 7:00 - +07 +-Link Asia/Bangkok Asia/Phnom_Penh # Cambodia +-Link Asia/Bangkok Asia/Vientiane # Laos +-Link Asia/Bangkok Indian/Christmas + + # Turkmenistan + # From Shanks & Pottenger. +@@ -3899,13 +3874,15 @@ Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad + 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00 + 5:00 - +05 + ++# Oman ++# Réunion ++# Seychelles + # United Arab Emirates ++# ++# The Crozet Is also observe Réunion time; see the 'antarctica' file. + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Dubai 3:41:12 - LMT 1920 + 4:00 - +04 +-Link Asia/Dubai Asia/Muscat # Oman +-Link Asia/Dubai Indian/Mahe +-Link Asia/Dubai Indian/Reunion + + # Uzbekistan + # Byalokoz 1919 says Uzbekistan was 4:27:53. +@@ -3925,7 +3902,7 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 + 5:00 RussiaAsia +05/+06 1992 + 5:00 - +05 + +-# Vietnam ++# Vietnam (southern) + + # From Paul Eggert (2014-10-04): + # Milne gives 7:16:56 for the meridian of Saigon in 1899, as being +@@ -3999,7 +3976,3 @@ Zone Asia/Ho_Chi_Minh 7:06:30 - LMT 1906 Jul 1 + # For timestamps in north Vietnam back to 1970 (the tzdb cutoff), + # use Asia/Bangkok; see the VN entries in the file zone1970.tab. + # For timestamps before 1970, see Asia/Hanoi in the file 'backzone'. +- +- +-# Yemen +-# See Asia/Riyadh. +diff --git a/jdk/make/data/tzdata/australasia b/jdk/make/data/tzdata/australasia +index 019cd77..fbe3b8a 100644 +--- a/jdk/make/data/tzdata/australasia ++++ b/jdk/make/data/tzdata/australasia +@@ -274,13 +274,6 @@ Zone Antarctica/Macquarie 0 - -00 1899 Nov + 10:00 1:00 AEDT 2011 + 10:00 AT AE%sT + +-# Christmas +-# See Asia/Bangkok. +- +-# Cocos (Keeling) Is +-# See Asia/Yangon. +- +- + # Fiji + + # Milne gives 11:55:44 for Suva. +@@ -416,8 +409,14 @@ Zone Antarctica/Macquarie 0 - -00 1899 Nov + # concerned shifting arrival and departure times, which may look like a simple + # thing but requires some significant logistical adjustments domestically and + # internationally." +-# Assume for now that DST will resume with the recent pre-2020 rules for the +-# 2022/2023 season. ++ ++# From Shalvin Narayan (2022-10-27): ++# Please note that there will not be any daylight savings time change ++# in Fiji for 2022-2023.... ++# https://www.facebook.com/FijianGovernment/posts/pfbid0mmWVTYmTibn66ybpFda75pDcf34SSpoSaskJW5gXwaKo5Sgc7273Q4fXWc6kQV6Hl ++# ++# From Paul Eggert (2022-10-27): ++# For now, assume DST is suspended indefinitely. + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Fiji 1998 1999 - Nov Sun>=1 2:00 1:00 - +@@ -432,8 +431,6 @@ Rule Fiji 2014 2018 - Nov Sun>=1 2:00 1:00 - + Rule Fiji 2015 2021 - Jan Sun>=12 3:00 0 - + Rule Fiji 2019 only - Nov Sun>=8 2:00 1:00 - + Rule Fiji 2020 only - Dec 20 2:00 1:00 - +-Rule Fiji 2022 max - Nov Sun>=8 2:00 1:00 - +-Rule Fiji 2023 max - Jan Sun>=12 3:00 0 - + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Pacific/Fiji 11:55:44 - LMT 1915 Oct 26 # Suva + 12:00 Fiji +12/+13 +@@ -449,7 +446,9 @@ Zone Pacific/Tahiti -9:58:16 - LMT 1912 Oct # Papeete + # Clipperton (near North America) is administered from French Polynesia; + # it is uninhabited. + ++ + # Guam ++# N Mariana Is + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + # http://guamlegislature.com/Public_Laws_5th/PL05-025.pdf +@@ -489,17 +488,20 @@ Zone Pacific/Guam -14:21:00 - LMT 1844 Dec 31 + 9:00 - +09 1944 Jul 31 + 10:00 Guam G%sT 2000 Dec 23 + 10:00 - ChST # Chamorro Standard Time +-Link Pacific/Guam Pacific/Saipan # N Mariana Is + +-# Kiribati ++ ++# Kiribati (Gilbert Is) ++# Marshall Is ++# Tuvalu ++# Wake ++# Wallis & Futuna + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Pacific/Tarawa 11:32:04 - LMT 1901 # Bairiki + 12:00 - +12 +-Link Pacific/Tarawa Pacific/Funafuti +-Link Pacific/Tarawa Pacific/Majuro +-Link Pacific/Tarawa Pacific/Wake +-Link Pacific/Tarawa Pacific/Wallis + ++# Kiribati (except Gilbert Is) ++# See Pacific/Tarawa for the Gilbert Is. ++# Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Pacific/Kanton 0 - -00 1937 Aug 31 + -12:00 - -12 1979 Oct + -11:00 - -11 1994 Dec 31 +@@ -509,9 +511,6 @@ Zone Pacific/Kiritimati -10:29:20 - LMT 1901 + -10:00 - -10 1994 Dec 31 + 14:00 - +14 + +-# N Mariana Is +-# See Pacific/Guam. +- + # Marshall Is + # See Pacific/Tarawa for most locations. + # Zone NAME STDOFF RULES FORMAT [UNTIL] +@@ -561,6 +560,7 @@ Zone Pacific/Noumea 11:05:48 - LMT 1912 Jan 13 # Nouméa + ############################################################################### + + # New Zealand ++# McMurdo Station and Scott Base in Antarctica use Auckland time. + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule NZ 1927 only - Nov 6 2:00 1:00 S +@@ -596,7 +596,6 @@ Rule Chatham 2008 max - Apr Sun>=1 2:45s 0 - + Zone Pacific/Auckland 11:39:04 - LMT 1868 Nov 2 + 11:30 NZ NZ%sT 1946 Jan 1 + 12:00 NZ NZ%sT +-Link Pacific/Auckland Antarctica/McMurdo + + Zone Pacific/Chatham 12:13:48 - LMT 1868 Nov 2 + 12:15 - +1215 1946 Jan 1 +@@ -695,8 +694,6 @@ Zone Pacific/Palau -15:02:04 - LMT 1844 Dec 31 # Koror + Zone Pacific/Port_Moresby 9:48:40 - LMT 1880 + 9:48:32 - PMMT 1895 # Port Moresby Mean Time + 10:00 - +10 +-Link Pacific/Port_Moresby Antarctica/DumontDUrville +-Link Pacific/Port_Moresby Pacific/Chuuk + # + # From Paul Eggert (2014-10-13): + # Base the Bougainville entry on the Arawa-Kieta region, which appears to have +@@ -729,10 +726,10 @@ Zone Pacific/Pitcairn -8:40:20 - LMT 1901 # Adamstown + -8:00 - -08 + + # American Samoa ++# Midway + Zone Pacific/Pago_Pago 12:37:12 - LMT 1892 Jul 5 + -11:22:48 - LMT 1911 + -11:00 - SST # S=Samoa +-Link Pacific/Pago_Pago Pacific/Midway # in US minor outlying islands + + # Samoa (formerly and also known as Western Samoa) + +@@ -824,7 +821,6 @@ Zone Pacific/Apia 12:33:04 - LMT 1892 Jul 5 + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct # Honiara + 11:00 - +11 +-Link Pacific/Guadalcanal Pacific/Pohnpei + + # Tokelau + # +@@ -864,9 +860,6 @@ Zone Pacific/Tongatapu 12:19:12 - LMT 1945 Sep 10 + 13:00 - +13 1999 + 13:00 Tonga +13/+14 + +-# Tuvalu +-# See Pacific/Tarawa. +- + + # US minor outlying islands + +@@ -917,15 +910,9 @@ Zone Pacific/Tongatapu 12:19:12 - LMT 1945 Sep 10 + # Kingman + # uninhabited + +-# Midway +-# See Pacific/Pago_Pago. +- + # Palmyra + # uninhabited since World War II; was probably like Pacific/Kiritimati + +-# Wake +-# See Pacific/Tarawa. +- + + # Vanuatu + +@@ -962,9 +949,6 @@ Rule Vanuatu 1992 only - Oct Sat>=22 24:00 1:00 - + Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila + 11:00 Vanuatu +11/+12 + +-# Wallis and Futuna +-# See Pacific/Tarawa. +- + ############################################################################### + + # NOTES +diff --git a/jdk/make/data/tzdata/backward b/jdk/make/data/tzdata/backward +index 7765d99..1fb087a 100644 +--- a/jdk/make/data/tzdata/backward ++++ b/jdk/make/data/tzdata/backward +@@ -27,7 +27,7 @@ + # 2009-05-17 by Arthur David Olson. + + # This file provides links from old or merged timezone names to current ones. +-# Many names changed in late 1993, and many merged names moved here ++# Many names changed in 1993 and in 1995, and many merged names moved here + # in the period from 2013 through 2022. Several of these names are + # also present in the file 'backzone', which has data important only + # for pre-1970 timestamps and so is out of scope for tzdb proper. +@@ -36,50 +36,24 @@ + # building with 'make BACKWARD=', in practice downstream users + # typically use this file for backward compatibility. + +-# Link TARGET LINK-NAME +-Link Africa/Nairobi Africa/Asmera +-Link Africa/Abidjan Africa/Timbuktu +-Link America/Argentina/Catamarca America/Argentina/ComodRivadavia +-Link America/Adak America/Atka +-Link America/Argentina/Buenos_Aires America/Buenos_Aires +-Link America/Argentina/Catamarca America/Catamarca +-Link America/Panama America/Coral_Harbour +-Link America/Argentina/Cordoba America/Cordoba +-Link America/Tijuana America/Ensenada +-Link America/Indiana/Indianapolis America/Fort_Wayne +-Link America/Nuuk America/Godthab +-Link America/Indiana/Indianapolis America/Indianapolis +-Link America/Argentina/Jujuy America/Jujuy +-Link America/Indiana/Knox America/Knox_IN +-Link America/Kentucky/Louisville America/Louisville +-Link America/Argentina/Mendoza America/Mendoza +-Link America/Toronto America/Montreal +-Link America/Rio_Branco America/Porto_Acre +-Link America/Argentina/Cordoba America/Rosario +-Link America/Tijuana America/Santa_Isabel +-Link America/Denver America/Shiprock +-Link America/Puerto_Rico America/Virgin +-Link Pacific/Auckland Antarctica/South_Pole +-Link Asia/Ashgabat Asia/Ashkhabad +-Link Asia/Kolkata Asia/Calcutta +-Link Asia/Shanghai Asia/Chongqing +-Link Asia/Shanghai Asia/Chungking +-Link Asia/Dhaka Asia/Dacca +-Link Asia/Shanghai Asia/Harbin +-Link Asia/Urumqi Asia/Kashgar +-Link Asia/Kathmandu Asia/Katmandu +-Link Asia/Macau Asia/Macao +-Link Asia/Yangon Asia/Rangoon +-Link Asia/Ho_Chi_Minh Asia/Saigon +-Link Asia/Jerusalem Asia/Tel_Aviv +-Link Asia/Thimphu Asia/Thimbu +-Link Asia/Makassar Asia/Ujung_Pandang +-Link Asia/Ulaanbaatar Asia/Ulan_Bator +-Link Atlantic/Faroe Atlantic/Faeroe +-Link Europe/Berlin Atlantic/Jan_Mayen +-Link Australia/Sydney Australia/ACT +-Link Australia/Sydney Australia/Canberra +-Link Australia/Hobart Australia/Currie ++# This file is divided into sections, one for each major reason for a ++# backward compatibility link. Each section is sorted by link name. ++ ++# A "#= TARGET1" comment labels each link inserted only because some ++# .zi parsers (including tzcode through 2022e) mishandle links to links. ++# The comment says what the target would be if these parsers were fixed ++# so that data could contain links to links. For example, the line ++# "Link Australia/Sydney Australia/ACT #= Australia/Canberra" would be ++# "Link Australia/Canberra Australia/ACT" were it not that data lines ++# refrain from linking to links like Australia/Canberra, which means ++# the Australia/ACT line links instead to Australia/Sydney, ++# Australia/Canberra's target. ++ ++ ++# Pre-1993 naming conventions ++ ++# Link TARGET LINK-NAME #= TARGET1 ++Link Australia/Sydney Australia/ACT #= Australia/Canberra + Link Australia/Lord_Howe Australia/LHI + Link Australia/Sydney Australia/NSW + Link Australia/Darwin Australia/North +@@ -89,7 +63,7 @@ Link Australia/Hobart Australia/Tasmania + Link Australia/Melbourne Australia/Victoria + Link Australia/Perth Australia/West + Link Australia/Broken_Hill Australia/Yancowinna +-Link America/Rio_Branco Brazil/Acre ++Link America/Rio_Branco Brazil/Acre #= America/Porto_Acre + Link America/Noronha Brazil/DeNoronha + Link America/Sao_Paulo Brazil/East + Link America/Manaus Brazil/West +@@ -109,20 +83,36 @@ Link Pacific/Easter Chile/EasterIsland + Link America/Havana Cuba + Link Africa/Cairo Egypt + Link Europe/Dublin Eire ++# Vanguard section, for most .zi parsers. ++#Link GMT Etc/GMT ++#Link GMT Etc/GMT+0 ++#Link GMT Etc/GMT-0 ++#Link GMT Etc/GMT0 ++#Link GMT Etc/Greenwich ++# Rearguard section, for TZUpdater 2.3.2 and earlier. ++Link Etc/GMT Etc/GMT+0 ++Link Etc/GMT Etc/GMT-0 ++Link Etc/GMT Etc/GMT0 ++Link Etc/GMT Etc/Greenwich ++# End of rearguard section. + Link Etc/UTC Etc/UCT +-Link Europe/London Europe/Belfast +-Link Europe/Kyiv Europe/Kiev +-Link Europe/Chisinau Europe/Tiraspol +-Link Europe/Kyiv Europe/Uzhgorod +-Link Europe/Kyiv Europe/Zaporozhye ++Link Etc/UTC Etc/Universal ++Link Etc/UTC Etc/Zulu + Link Europe/London GB + Link Europe/London GB-Eire ++# Vanguard section, for most .zi parsers. ++#Link GMT GMT+0 ++#Link GMT GMT-0 ++#Link GMT GMT0 ++#Link GMT Greenwich ++# Rearguard section, for TZUpdater 2.3.2 and earlier. + Link Etc/GMT GMT+0 + Link Etc/GMT GMT-0 + Link Etc/GMT GMT0 + Link Etc/GMT Greenwich ++# End of rearguard section. + Link Asia/Hong_Kong Hongkong +-Link Africa/Abidjan Iceland ++Link Africa/Abidjan Iceland #= Atlantic/Reykjavik + Link Asia/Tehran Iran + Link Asia/Jerusalem Israel + Link America/Jamaica Jamaica +@@ -134,14 +124,8 @@ Link America/Mazatlan Mexico/BajaSur + Link America/Mexico_City Mexico/General + Link Pacific/Auckland NZ + Link Pacific/Chatham NZ-CHAT +-Link America/Denver Navajo ++Link America/Denver Navajo #= America/Shiprock + Link Asia/Shanghai PRC +-Link Pacific/Kanton Pacific/Enderbury +-Link Pacific/Honolulu Pacific/Johnston +-Link Pacific/Guadalcanal Pacific/Ponape +-Link Pacific/Pago_Pago Pacific/Samoa +-Link Pacific/Port_Moresby Pacific/Truk +-Link Pacific/Port_Moresby Pacific/Yap + Link Europe/Warsaw Poland + Link Europe/Lisbon Portugal + Link Asia/Taipei ROC +@@ -165,3 +149,192 @@ Link Etc/UTC UTC + Link Etc/UTC Universal + Link Europe/Moscow W-SU + Link Etc/UTC Zulu ++ ++ ++# Two-part names that were renamed mostly to three-part names in 1995 ++ ++# Link TARGET LINK-NAME #= TARGET1 ++Link America/Argentina/Buenos_Aires America/Buenos_Aires ++Link America/Argentina/Catamarca America/Catamarca ++Link America/Argentina/Cordoba America/Cordoba ++Link America/Indiana/Indianapolis America/Indianapolis ++Link America/Argentina/Jujuy America/Jujuy ++Link America/Indiana/Knox America/Knox_IN ++Link America/Kentucky/Louisville America/Louisville ++Link America/Argentina/Mendoza America/Mendoza ++Link America/Puerto_Rico America/Virgin #= America/St_Thomas ++Link Pacific/Pago_Pago Pacific/Samoa ++ ++ ++# Pre-2013 practice, which typically had a Zone per zone.tab line ++ ++# Link TARGET LINK-NAME ++Link Africa/Abidjan Africa/Accra ++Link Africa/Nairobi Africa/Addis_Ababa ++Link Africa/Nairobi Africa/Asmara ++Link Africa/Abidjan Africa/Bamako ++Link Africa/Lagos Africa/Bangui ++Link Africa/Abidjan Africa/Banjul ++Link Africa/Maputo Africa/Blantyre ++Link Africa/Lagos Africa/Brazzaville ++Link Africa/Maputo Africa/Bujumbura ++Link Africa/Abidjan Africa/Conakry ++Link Africa/Abidjan Africa/Dakar ++Link Africa/Nairobi Africa/Dar_es_Salaam ++Link Africa/Nairobi Africa/Djibouti ++Link Africa/Lagos Africa/Douala ++Link Africa/Abidjan Africa/Freetown ++Link Africa/Maputo Africa/Gaborone ++Link Africa/Maputo Africa/Harare ++Link Africa/Nairobi Africa/Kampala ++Link Africa/Maputo Africa/Kigali ++Link Africa/Lagos Africa/Kinshasa ++Link Africa/Lagos Africa/Libreville ++Link Africa/Abidjan Africa/Lome ++Link Africa/Lagos Africa/Luanda ++Link Africa/Maputo Africa/Lubumbashi ++Link Africa/Maputo Africa/Lusaka ++Link Africa/Lagos Africa/Malabo ++Link Africa/Johannesburg Africa/Maseru ++Link Africa/Johannesburg Africa/Mbabane ++Link Africa/Nairobi Africa/Mogadishu ++Link Africa/Lagos Africa/Niamey ++Link Africa/Abidjan Africa/Nouakchott ++Link Africa/Abidjan Africa/Ouagadougou ++Link Africa/Lagos Africa/Porto-Novo ++Link America/Puerto_Rico America/Anguilla ++Link America/Puerto_Rico America/Antigua ++Link America/Puerto_Rico America/Aruba ++Link America/Panama America/Atikokan ++Link America/Puerto_Rico America/Blanc-Sablon ++Link America/Panama America/Cayman ++Link America/Phoenix America/Creston ++Link America/Puerto_Rico America/Curacao ++Link America/Puerto_Rico America/Dominica ++Link America/Puerto_Rico America/Grenada ++Link America/Puerto_Rico America/Guadeloupe ++Link America/Puerto_Rico America/Kralendijk ++Link America/Puerto_Rico America/Lower_Princes ++Link America/Puerto_Rico America/Marigot ++Link America/Puerto_Rico America/Montserrat ++Link America/Toronto America/Nassau ++Link America/Puerto_Rico America/Port_of_Spain ++Link America/Puerto_Rico America/St_Barthelemy ++Link America/Puerto_Rico America/St_Kitts ++Link America/Puerto_Rico America/St_Lucia ++Link America/Puerto_Rico America/St_Thomas ++Link America/Puerto_Rico America/St_Vincent ++Link America/Puerto_Rico America/Tortola ++Link Pacific/Port_Moresby Antarctica/DumontDUrville ++Link Pacific/Auckland Antarctica/McMurdo ++Link Asia/Riyadh Antarctica/Syowa ++Link Asia/Urumqi Antarctica/Vostok ++Link Europe/Berlin Arctic/Longyearbyen ++Link Asia/Riyadh Asia/Aden ++Link Asia/Qatar Asia/Bahrain ++Link Asia/Kuching Asia/Brunei ++Link Asia/Singapore Asia/Kuala_Lumpur ++Link Asia/Riyadh Asia/Kuwait ++Link Asia/Dubai Asia/Muscat ++Link Asia/Bangkok Asia/Phnom_Penh ++Link Asia/Bangkok Asia/Vientiane ++Link Africa/Abidjan Atlantic/Reykjavik ++Link Africa/Abidjan Atlantic/St_Helena ++Link Europe/Brussels Europe/Amsterdam ++Link Europe/Prague Europe/Bratislava ++Link Europe/Zurich Europe/Busingen ++Link Europe/Berlin Europe/Copenhagen ++Link Europe/London Europe/Guernsey ++Link Europe/London Europe/Isle_of_Man ++Link Europe/London Europe/Jersey ++Link Europe/Belgrade Europe/Ljubljana ++Link Europe/Brussels Europe/Luxembourg ++Link Europe/Helsinki Europe/Mariehamn ++Link Europe/Paris Europe/Monaco ++Link Europe/Berlin Europe/Oslo ++Link Europe/Belgrade Europe/Podgorica ++Link Europe/Rome Europe/San_Marino ++Link Europe/Belgrade Europe/Sarajevo ++Link Europe/Belgrade Europe/Skopje ++Link Europe/Berlin Europe/Stockholm ++Link Europe/Zurich Europe/Vaduz ++Link Europe/Rome Europe/Vatican ++Link Europe/Belgrade Europe/Zagreb ++Link Africa/Nairobi Indian/Antananarivo ++Link Asia/Bangkok Indian/Christmas ++Link Asia/Yangon Indian/Cocos ++Link Africa/Nairobi Indian/Comoro ++Link Indian/Maldives Indian/Kerguelen ++Link Asia/Dubai Indian/Mahe ++Link Africa/Nairobi Indian/Mayotte ++Link Asia/Dubai Indian/Reunion ++Link Pacific/Port_Moresby Pacific/Chuuk ++Link Pacific/Tarawa Pacific/Funafuti ++Link Pacific/Tarawa Pacific/Majuro ++Link Pacific/Pago_Pago Pacific/Midway ++Link Pacific/Guadalcanal Pacific/Pohnpei ++Link Pacific/Guam Pacific/Saipan ++Link Pacific/Tarawa Pacific/Wake ++Link Pacific/Tarawa Pacific/Wallis ++ ++ ++# Non-zone.tab locations with timestamps since 1970 that duplicate ++# those of an existing location ++ ++# Link TARGET LINK-NAME ++Link Africa/Abidjan Africa/Timbuktu ++Link America/Argentina/Catamarca America/Argentina/ComodRivadavia ++Link America/Adak America/Atka ++Link America/Panama America/Coral_Harbour ++Link America/Tijuana America/Ensenada ++Link America/Indiana/Indianapolis America/Fort_Wayne ++Link America/Toronto America/Montreal ++Link America/Toronto America/Nipigon ++Link America/Rio_Branco America/Porto_Acre ++Link America/Winnipeg America/Rainy_River ++Link America/Argentina/Cordoba America/Rosario ++Link America/Tijuana America/Santa_Isabel ++Link America/Denver America/Shiprock ++Link America/Toronto America/Thunder_Bay ++Link Pacific/Auckland Antarctica/South_Pole ++Link Asia/Shanghai Asia/Chongqing ++Link Asia/Shanghai Asia/Harbin ++Link Asia/Urumqi Asia/Kashgar ++Link Asia/Jerusalem Asia/Tel_Aviv ++Link Europe/Berlin Atlantic/Jan_Mayen ++Link Australia/Sydney Australia/Canberra ++Link Australia/Hobart Australia/Currie ++Link Europe/London Europe/Belfast ++Link Europe/Chisinau Europe/Tiraspol ++Link Europe/Kyiv Europe/Uzhgorod ++Link Europe/Kyiv Europe/Zaporozhye ++Link Pacific/Kanton Pacific/Enderbury ++Link Pacific/Honolulu Pacific/Johnston ++Link Pacific/Port_Moresby Pacific/Yap ++ ++ ++# Alternate names for the same location ++ ++# Link TARGET LINK-NAME #= TARGET1 ++Link Africa/Nairobi Africa/Asmera #= Africa/Asmara ++Link America/Nuuk America/Godthab ++Link Asia/Ashgabat Asia/Ashkhabad ++Link Asia/Kolkata Asia/Calcutta ++Link Asia/Shanghai Asia/Chungking #= Asia/Chongqing ++Link Asia/Dhaka Asia/Dacca ++# Istanbul is in both continents. ++Link Europe/Istanbul Asia/Istanbul ++Link Asia/Kathmandu Asia/Katmandu ++Link Asia/Macau Asia/Macao ++Link Asia/Yangon Asia/Rangoon ++Link Asia/Ho_Chi_Minh Asia/Saigon ++Link Asia/Thimphu Asia/Thimbu ++Link Asia/Makassar Asia/Ujung_Pandang ++Link Asia/Ulaanbaatar Asia/Ulan_Bator ++Link Atlantic/Faroe Atlantic/Faeroe ++Link Europe/Kyiv Europe/Kiev ++# Classically, Cyprus is in Asia; e.g. see Herodotus, Histories, I.72. ++# However, for various reasons many users expect to find it under Europe. ++Link Asia/Nicosia Europe/Nicosia ++Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei ++Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk +diff --git a/jdk/make/data/tzdata/etcetera b/jdk/make/data/tzdata/etcetera +index 82ff6b4..8ae294f 100644 +--- a/jdk/make/data/tzdata/etcetera ++++ b/jdk/make/data/tzdata/etcetera +@@ -39,26 +39,23 @@ + # Do not use a POSIX TZ setting like TZ='GMT+4', which is four hours + # behind GMT but uses the completely misleading abbreviation "GMT". + +-Zone Etc/GMT 0 - GMT +- + # The following zone is used by tzcode functions like gmtime, + # which load the "UTC" file to handle seconds properly. + Zone Etc/UTC 0 - UTC + ++# Functions like gmtime load the "GMT" file to handle leap seconds properly. ++# Vanguard section, which works with most .zi parsers. ++#Zone GMT 0 - GMT ++# Rearguard section, for TZUpdater 2.3.2 and earlier. ++Zone Etc/GMT 0 - GMT ++ + # The following link uses older naming conventions, + # but it belongs here, not in the file 'backward', + # as it is needed for tzcode releases through 2022a, + # where functions like gmtime load "GMT" instead of the "Etc/UTC". + # We want this to work even on installations that omit 'backward'. + Link Etc/GMT GMT +- +-Link Etc/UTC Etc/Universal +-Link Etc/UTC Etc/Zulu +- +-Link Etc/GMT Etc/Greenwich +-Link Etc/GMT Etc/GMT-0 +-Link Etc/GMT Etc/GMT+0 +-Link Etc/GMT Etc/GMT0 ++# End of rearguard section. + + # Be consistent with POSIX TZ settings in the Zone names, + # even though this is the opposite of what many people expect. +diff --git a/jdk/make/data/tzdata/europe b/jdk/make/data/tzdata/europe +index 930cede..7b6aa13 100644 +--- a/jdk/make/data/tzdata/europe ++++ b/jdk/make/data/tzdata/europe +@@ -527,9 +527,6 @@ Zone Europe/London -0:01:15 - LMT 1847 Dec 1 + 1:00 - BST 1971 Oct 31 2:00u + 0:00 GB-Eire %s 1996 + 0:00 EU GMT/BST +-Link Europe/London Europe/Jersey +-Link Europe/London Europe/Guernsey +-Link Europe/London Europe/Isle_of_Man + + # From Paul Eggert (2018-02-15): + # In January 2018 we discovered that the negative SAVE values in the +@@ -902,6 +899,8 @@ Zone Europe/Minsk 1:50:16 - LMT 1880 + 3:00 - +03 + + # Belgium ++# Luxembourg ++# Netherlands + # + # From Michael Deckers (2019-08-25): + # The exposition in the web page +@@ -984,11 +983,6 @@ Zone Europe/Brussels 0:17:30 - LMT 1880 + 1:00 C-Eur CE%sT 1944 Sep 3 + 1:00 Belgium CE%sT 1977 + 1:00 EU CE%sT +-Link Europe/Brussels Europe/Amsterdam +-Link Europe/Brussels Europe/Luxembourg +- +-# Bosnia and Herzegovina +-# See Europe/Belgrade. + + # Bulgaria + # +@@ -1015,13 +1009,11 @@ Zone Europe/Sofia 1:33:16 - LMT 1880 + 2:00 E-Eur EE%sT 1997 + 2:00 EU EE%sT + +-# Croatia +-# See Europe/Belgrade. +- + # Cyprus + # Please see the 'asia' file for Asia/Nicosia. + +-# Czech Republic / Czechia ++# Czech Republic (Czechia) ++# Slovakia + # + # From Paul Eggert (2018-04-15): + # The source for Czech data is: Kdy začíná a končí letní čas. 2018-04-15. +@@ -1048,15 +1040,14 @@ Zone Europe/Prague 0:57:44 - LMT 1850 + # End of rearguard section. + 1:00 Czech CE%sT 1979 + 1:00 EU CE%sT +-Link Europe/Prague Europe/Bratislava +- +- +-# Denmark, Faroe Islands, and Greenland +-# For Denmark see Europe/Berlin. + ++# Faroe Is ++# Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Atlantic/Faroe -0:27:04 - LMT 1908 Jan 11 # Tórshavn + 0:00 - WET 1981 + 0:00 EU WE%sT ++ ++# Greenland + # + # From Paul Eggert (2004-10-31): + # During World War II, Germany maintained secret manned weather stations in +@@ -1282,11 +1273,8 @@ Zone Europe/Helsinki 1:39:49 - LMT 1878 May 31 + 2:00 Finland EE%sT 1983 + 2:00 EU EE%sT + +-# Åland Is +-Link Europe/Helsinki Europe/Mariehamn +- +- + # France ++# Monaco + + # From Ciro Discepolo (2000-12-20): + # +@@ -1423,9 +1411,11 @@ Zone Europe/Paris 0:09:21 - LMT 1891 Mar 16 + 0:00 France WE%sT 1945 Sep 16 3:00 + 1:00 France CE%sT 1977 + 1:00 EU CE%sT +-Link Europe/Paris Europe/Monaco + ++# Denmark + # Germany ++# Norway ++# Sweden + + # From Markus Kuhn (1998-09-29): + # The German time zone web site by the Physikalisch-Technische +@@ -1443,6 +1433,53 @@ Link Europe/Paris Europe/Monaco + # However, Moscow did not observe daylight saving in 1945, so + # this was equivalent to UT +03, not +04. + ++# Svalbard & Jan Mayen ++ ++# From Steffen Thorsen (2001-05-01): ++# Although I could not find it explicitly, it seems that Jan Mayen and ++# Svalbard have been using the same time as Norway at least since the ++# time they were declared as parts of Norway. Svalbard was declared ++# as a part of Norway by law of 1925-07-17 no 11, section 4 and Jan ++# Mayen by law of 1930-02-27 no 2, section 2. (From ++# and ++# ). The law/regulation ++# for normal/standard time in Norway is from 1894-06-29 no 1 (came ++# into operation on 1895-01-01) and Svalbard/Jan Mayen seem to be a ++# part of this law since 1925/1930. (From ++# ) I have not been ++# able to find if Jan Mayen used a different time zone (e.g. -0100) ++# before 1930. Jan Mayen has only been "inhabited" since 1921 by ++# Norwegian meteorologists and maybe used the same time as Norway ever ++# since 1921. Svalbard (Arctic/Longyearbyen) has been inhabited since ++# before 1895, and therefore probably changed the local time somewhere ++# between 1895 and 1925 (inclusive). ++ ++# From Paul Eggert (2013-09-04): ++# ++# Actually, Jan Mayen was never occupied by Germany during World War II, ++# so it must have diverged from Oslo time during the war, as Oslo was ++# keeping Berlin time. ++# ++# says that the meteorologists ++# burned down their station in 1940 and left the island, but returned in ++# 1941 with a small Norwegian garrison and continued operations despite ++# frequent air attacks from Germans. In 1943 the Americans established a ++# radiolocating station on the island, called "Atlantic City". Possibly ++# the UT offset changed during the war, but I think it unlikely that ++# Jan Mayen used German daylight-saving rules. ++# ++# Svalbard is more complicated, as it was raided in August 1941 by an ++# Allied party that evacuated the civilian population to England (says ++# ). The Svalbard FAQ ++# says that the Germans were ++# expelled on 1942-05-14. However, small parties of Germans did return, ++# and according to Wilhelm Dege's book "War North of 80" (1954) ++# http://www.ucalgary.ca/UofC/departments/UP/1-55238/1-55238-110-2.html ++# the German armed forces at the Svalbard weather station code-named ++# Haudegen did not surrender to the Allies until September 1945. ++# ++# All these events predate our cutoff date of 1970, so use Europe/Berlin ++# for these regions. + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Germany 1946 only - Apr 14 2:00s 1:00 S +@@ -1467,11 +1504,6 @@ Zone Europe/Berlin 0:53:28 - LMT 1893 Apr + 1:00 SovietZone CE%sT 1946 + 1:00 Germany CE%sT 1980 + 1:00 EU CE%sT +-Link Europe/Berlin Arctic/Longyearbyen +-Link Europe/Berlin Europe/Copenhagen +-Link Europe/Berlin Europe/Oslo +-Link Europe/Berlin Europe/Stockholm +- + + # Georgia + # Please see the "asia" file for Asia/Tbilisi. +@@ -1590,10 +1622,9 @@ Zone Europe/Budapest 1:16:20 - LMT 1890 Nov 1 + 1:00 Hungary CE%sT 1984 + 1:00 EU CE%sT + +-# Iceland +-# See Africa/Abidjan. +- + # Italy ++# San Marino ++# Vatican City + # + # From Paul Eggert (2001-03-06): + # Sicily and Sardinia each had their own time zones from 1866 to 1893, +@@ -1712,13 +1743,6 @@ Zone Europe/Rome 0:49:56 - LMT 1866 Dec 12 + 1:00 C-Eur CE%sT 1944 Jun 4 + 1:00 Italy CE%sT 1980 + 1:00 EU CE%sT +-Link Europe/Rome Europe/Vatican +-Link Europe/Rome Europe/San_Marino +- +- +-# Kosovo +-# See Europe/Belgrade. +- + + # Latvia + +@@ -1802,10 +1826,6 @@ Zone Europe/Riga 1:36:34 - LMT 1880 + 2:00 - EET 2001 Jan 2 + 2:00 EU EE%sT + +-# Liechtenstein +-# See Europe/Zurich. +- +- + # Lithuania + + # From Paul Eggert (2016-03-18): +@@ -1858,12 +1878,6 @@ Zone Europe/Vilnius 1:41:16 - LMT 1880 + 2:00 - EET 2003 Jan 1 + 2:00 EU EE%sT + +-# Luxembourg +-# See Europe/Brussels. +- +-# North Macedonia +-# See Europe/Belgrade. +- + # Malta + # + # From Paul Eggert (2016-10-21): +@@ -1959,67 +1973,6 @@ Zone Europe/Chisinau 1:55:20 - LMT 1880 + # See Romania commentary for the guessed 1997 transition to EU rules. + 2:00 Moldova EE%sT + +-# Monaco +-# See Europe/Paris. +- +-# Montenegro +-# See Europe/Belgrade. +- +-# Netherlands +-# See Europe/Brussels. +- +-# Norway +-# See Europe/Berlin. +- +-# Svalbard & Jan Mayen +- +-# From Steffen Thorsen (2001-05-01): +-# Although I could not find it explicitly, it seems that Jan Mayen and +-# Svalbard have been using the same time as Norway at least since the +-# time they were declared as parts of Norway. Svalbard was declared +-# as a part of Norway by law of 1925-07-17 no 11, section 4 and Jan +-# Mayen by law of 1930-02-27 no 2, section 2. (From +-# and +-# ). The law/regulation +-# for normal/standard time in Norway is from 1894-06-29 no 1 (came +-# into operation on 1895-01-01) and Svalbard/Jan Mayen seem to be a +-# part of this law since 1925/1930. (From +-# ) I have not been +-# able to find if Jan Mayen used a different time zone (e.g. -0100) +-# before 1930. Jan Mayen has only been "inhabited" since 1921 by +-# Norwegian meteorologists and maybe used the same time as Norway ever +-# since 1921. Svalbard (Arctic/Longyearbyen) has been inhabited since +-# before 1895, and therefore probably changed the local time somewhere +-# between 1895 and 1925 (inclusive). +- +-# From Paul Eggert (2013-09-04): +-# +-# Actually, Jan Mayen was never occupied by Germany during World War II, +-# so it must have diverged from Oslo time during the war, as Oslo was +-# keeping Berlin time. +-# +-# says that the meteorologists +-# burned down their station in 1940 and left the island, but returned in +-# 1941 with a small Norwegian garrison and continued operations despite +-# frequent air attacks from Germans. In 1943 the Americans established a +-# radiolocating station on the island, called "Atlantic City". Possibly +-# the UT offset changed during the war, but I think it unlikely that +-# Jan Mayen used German daylight-saving rules. +-# +-# Svalbard is more complicated, as it was raided in August 1941 by an +-# Allied party that evacuated the civilian population to England (says +-# ). The Svalbard FAQ +-# says that the Germans were +-# expelled on 1942-05-14. However, small parties of Germans did return, +-# and according to Wilhelm Dege's book "War North of 80" (1954) +-# http://www.ucalgary.ca/UofC/departments/UP/1-55238/1-55238-110-2.html +-# the German armed forces at the Svalbard weather station code-named +-# Haudegen did not surrender to the Allies until September 1945. +-# +-# All these events predate our cutoff date of 1970, so use Europe/Berlin +-# for these regions. +- +- + # Poland + + # The 1919 dates and times can be found in Tygodnik Urzędowy nr 1 (1919-03-20), +@@ -3301,11 +3254,13 @@ Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2 + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 + +- +-# San Marino +-# See Europe/Rome. +- ++# Bosnia & Herzegovina ++# Croatia ++# Kosovo ++# Montenegro ++# North Macedonia + # Serbia ++# Slovenia + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Europe/Belgrade 1:22:00 - LMT 1884 + 1:00 - CET 1941 Apr 18 23:00 +@@ -3317,17 +3272,6 @@ Zone Europe/Belgrade 1:22:00 - LMT 1884 + # Shanks & Pottenger don't give as much detail, so go with Koželj. + 1:00 - CET 1982 Nov 27 + 1:00 EU CE%sT +-Link Europe/Belgrade Europe/Ljubljana # Slovenia +-Link Europe/Belgrade Europe/Podgorica # Montenegro +-Link Europe/Belgrade Europe/Sarajevo # Bosnia and Herzegovina +-Link Europe/Belgrade Europe/Skopje # North Macedonia +-Link Europe/Belgrade Europe/Zagreb # Croatia +- +-# Slovakia +-# See Europe/Prague. +- +-# Slovenia +-# See Europe/Belgrade. + + # Spain + # +@@ -3434,10 +3378,11 @@ Zone Atlantic/Canary -1:01:36 - LMT 1922 Mar # Las Palmas de Gran C. + # IATA SSIM (1996-09) says the Canaries switch at 2:00u, not 1:00u. + # Ignore this for now, as the Canaries are part of the EU. + +-# Sweden +-# See Europe/Berlin. + ++# Germany (Busingen enclave) ++# Liechtenstein + # Switzerland ++# + # From Howse: + # By the end of the 18th century clocks and watches became commonplace + # and their performance improved enormously. Communities began to keep +@@ -3550,9 +3495,6 @@ Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16 # See above comment. + 0:29:46 - BMT 1894 Jun # Bern Mean Time + 1:00 Swiss CE%sT 1981 + 1:00 EU CE%sT +-Link Europe/Zurich Europe/Busingen +-Link Europe/Zurich Europe/Vaduz +- + + # Turkey + +@@ -3757,7 +3699,6 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880 + 2:00 1:00 EEST 2015 Nov 8 1:00u + 2:00 EU EE%sT 2016 Sep 7 + 3:00 - +03 +-Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. + + # Ukraine + # +@@ -3860,9 +3801,6 @@ Zone Europe/Kyiv 2:02:04 - LMT 1880 + 2:00 C-Eur EE%sT 1996 May 13 + 2:00 EU EE%sT + +-# Vatican City +-# See Europe/Rome. +- + ############################################################################### + + # One source shows that Bulgaria, Cyprus, Finland, and Greece observe DST from +diff --git a/jdk/make/data/tzdata/northamerica b/jdk/make/data/tzdata/northamerica +index ce4ee74..465e8c2 100644 +--- a/jdk/make/data/tzdata/northamerica ++++ b/jdk/make/data/tzdata/northamerica +@@ -852,7 +852,6 @@ Zone America/Phoenix -7:28:18 - LMT 1883 Nov 18 19:00u + -7:00 - MST 1967 + -7:00 US M%sT 1968 Mar 21 + -7:00 - MST +-Link America/Phoenix America/Creston + + # From Arthur David Olson (1988-02-13): + # A writer from the Inter Tribal Council of Arizona, Inc., +@@ -1626,23 +1625,6 @@ Zone America/Moncton -4:19:08 - LMT 1883 Dec 9 + + # Ontario + +-# From Paul Eggert (2006-07-09): +-# Shanks & Pottenger write that since 1970 most of Ontario has been like +-# Toronto. +-# Thunder Bay skipped DST in 1973. +-# Many smaller locales did not observe peacetime DST until 1974; +-# Nipigon (EST) and Rainy River (CST) are the largest that we know of. +-# Far west Ontario is like Winnipeg; far east Quebec is like Halifax. +- +-# From Jeffery Nichols (2020-02-06): +-# According to the [Shanks] atlas, those western Ontario zones are huge, +-# covering most of Ontario northwest of Sault Ste Marie and Timmins. +-# The zones seem to include towns bigger than the ones they're named after, +-# like Dryden in America/Rainy_River and Wawa (and maybe Attawapiskat) in +-# America/Nipigon. I assume it's too much trouble to change the name of the +-# zone (like when you found out that America/Glace_Bay includes Sydney, Nova +-# Scotia).... +- + # From Mark Brader (2003-07-26): + # [According to the Toronto Star] Orillia, Ontario, adopted DST + # effective Saturday, 1912-06-22, 22:00; the article mentions that +@@ -1663,17 +1645,6 @@ Zone America/Moncton -4:19:08 - LMT 1883 Dec 9 + + # From Mark Brader (2010-03-06): + # +-# Currently the database has: +-# +-# # Ontario +-# +-# # From Paul Eggert (2006-07-09): +-# # Shanks & Pottenger write that since 1970 most of Ontario has been like +-# # Toronto. +-# # Thunder Bay skipped DST in 1973. +-# # Many smaller locales did not observe peacetime DST until 1974; +-# # Nipigon (EST) and Rainy River (CST) are the largest that we know of. +-# + # In the (Toronto) Globe and Mail for Saturday, 1955-09-24, in the bottom + # right corner of page 1, it says that Toronto will return to standard + # time at 2 am Sunday morning (which agrees with the database), and that: +@@ -1681,10 +1652,8 @@ Zone America/Moncton -4:19:08 - LMT 1883 Dec 9 + # The one-hour setback will go into effect throughout most of Ontario, + # except in areas like Windsor which remains on standard time all year. + # +-# Windsor is, of course, a lot larger than Nipigon. +-# +-# I only came across this incidentally. I don't know if Windsor began +-# observing DST when Detroit did, or in 1974, or on some other date. ++# ... I don't know if Windsor began observing DST when Detroit did, ++# or in 1974, or on some other date. + # + # By the way, the article continues by noting that: + # +@@ -1766,23 +1735,7 @@ Rule Toronto 1951 1956 - Sep lastSun 2:00 0 S + # Toronto Star, which said that DST was ending 1971-10-31 as usual. + Rule Toronto 1957 1973 - Oct lastSun 2:00 0 S + +-# From Paul Eggert (2003-07-27): +-# Willett (1914-03) writes (p. 17) "In the Cities of Fort William, and +-# Port Arthur, Ontario, the principle of the Bill has been in +-# operation for the past three years, and in the City of Moose Jaw, +-# Saskatchewan, for one year." +- +-# From David Bryan via Tory Tronrud, Director/Curator, +-# Thunder Bay Museum (2003-11-12): +-# There is some suggestion, however, that, by-law or not, daylight +-# savings time was being practiced in Fort William and Port Arthur +-# before 1909.... [I]n 1910, the line between the Eastern and Central +-# Time Zones was permanently moved about two hundred miles west to +-# include the Thunder Bay area.... When Canada adopted daylight +-# savings time in 1916, Fort William and Port Arthur, having done so +-# already, did not change their clocks.... During the Second World +-# War,... [t]he cities agreed to implement DST during the summer +-# months for the remainder of the war years. ++# The Bahamas match Toronto since 1970. + + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone America/Toronto -5:17:32 - LMT 1895 +@@ -1791,22 +1744,6 @@ Zone America/Toronto -5:17:32 - LMT 1895 + -5:00 Canada E%sT 1946 + -5:00 Toronto E%sT 1974 + -5:00 Canada E%sT +-Link America/Toronto America/Nassau +-Zone America/Thunder_Bay -5:57:00 - LMT 1895 +- -6:00 - CST 1910 +- -5:00 - EST 1942 +- -5:00 Canada E%sT 1970 +- -5:00 Toronto E%sT 1973 +- -5:00 - EST 1974 +- -5:00 Canada E%sT +-Zone America/Nipigon -5:53:04 - LMT 1895 +- -5:00 Canada E%sT 1940 Sep 29 +- -5:00 1:00 EDT 1942 Feb 9 2:00s +- -5:00 Canada E%sT +-Zone America/Rainy_River -6:18:16 - LMT 1895 +- -6:00 Canada C%sT 1940 Sep 29 +- -6:00 1:00 CDT 1942 Feb 9 2:00s +- -6:00 Canada C%sT + # For Atikokan see America/Panama. + + +@@ -2639,6 +2576,12 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 + # 5- The islands, reefs and keys shall take their timezone from the + # longitude they are located at. + ++# From Paul Eggert (2022-10-28): ++# The new Mexican law was published today: ++# https://www.dof.gob.mx/nota_detalle.php?codigo=5670045&fecha=28/10/2022 ++# This abolishes DST except where US DST rules are observed, ++# and in addition changes all of Chihuahua to -06 with no DST. ++ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Mexico 1931 only - May 1 23:00 1:00 D + Rule Mexico 1931 only - Oct 1 0:00 0 S +@@ -2654,8 +2597,8 @@ Rule Mexico 1996 2000 - Apr Sun>=1 2:00 1:00 D + Rule Mexico 1996 2000 - Oct lastSun 2:00 0 S + Rule Mexico 2001 only - May Sun>=1 2:00 1:00 D + Rule Mexico 2001 only - Sep lastSun 2:00 0 S +-Rule Mexico 2002 max - Apr Sun>=1 2:00 1:00 D +-Rule Mexico 2002 max - Oct lastSun 2:00 0 S ++Rule Mexico 2002 2022 - Apr Sun>=1 2:00 1:00 D ++Rule Mexico 2002 2022 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] + # Quintana Roo; represented by Cancún + Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 6:00u +@@ -2708,7 +2651,8 @@ Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u + -6:00 Mexico C%sT 1998 + -6:00 - CST 1998 Apr Sun>=1 3:00 + -7:00 Mexico M%sT 2010 +- -7:00 US M%sT ++ -7:00 US M%sT 2022 Oct 30 2:00 ++ -6:00 - CST + # Chihuahua (away from US border) + Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 +@@ -2717,7 +2661,8 @@ Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u + -6:00 - CST 1996 + -6:00 Mexico C%sT 1998 + -6:00 - CST 1998 Apr Sun>=1 3:00 +- -7:00 Mexico M%sT ++ -7:00 Mexico M%sT 2022 Oct 30 2:00 ++ -6:00 - CST + # Sonora + Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 +@@ -2815,20 +2760,16 @@ Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 7:00u + # http://dof.gob.mx/nota_detalle.php?codigo=5127480&fecha=06/01/2010 + # It has been moved to the 'backward' file. + # ++# From Paul Eggert (2022-10-28): ++# Today's new law states that the entire state of Baja California ++# follows US DST rules, which agrees with simplifications noted above. ++# + # + # Revillagigedo Is + # no information + + ############################################################################### + +-# Anguilla +-# Antigua and Barbuda +-# See America/Puerto_Rico. +- +-# The Bahamas +-# See America/Toronto. +- +- + # Barbados + + # For 1899 Milne gives -3:58:29.2. +@@ -3041,12 +2982,6 @@ Zone Atlantic/Bermuda -4:19:18 - LMT 1890 # Hamilton + -4:00 Canada A%sT 1976 + -4:00 US A%sT + +-# Caribbean Netherlands +-# See America/Puerto_Rico. +- +-# Cayman Is +-# See America/Panama. +- + # Costa Rica + + # Milne gives -5:36:13.3 as San José mean time. +@@ -3272,9 +3207,6 @@ Zone America/Havana -5:29:28 - LMT 1890 + -5:29:36 - HMT 1925 Jul 19 12:00 # Havana MT + -5:00 Cuba C%sT + +-# Dominica +-# See America/Puerto_Rico. +- + # Dominican Republic + + # From Steffen Thorsen (2000-10-30): +@@ -3321,12 +3253,6 @@ Rule Salv 1987 1988 - Sep lastSun 0:00 0 S + Zone America/El_Salvador -5:56:48 - LMT 1921 # San Salvador + -6:00 Salv C%sT + +-# Grenada +-# Guadeloupe +-# St Barthélemy +-# St Martin (French part) +-# See America/Puerto_Rico. +- + # Guatemala + # + # From Gwillim Law (2006-04-22), after a heads-up from Oscar van Vlijmen: +@@ -3512,9 +3438,6 @@ Zone America/Martinique -4:04:20 - LMT 1890 # Fort-de-France + -4:00 1:00 ADT 1980 Sep 28 + -4:00 - AST + +-# Montserrat +-# See America/Puerto_Rico. +- + # Nicaragua + # + # This uses Shanks & Pottenger for times before 2005. +@@ -3580,44 +3503,39 @@ Zone America/Managua -5:45:08 - LMT 1890 + -5:00 - EST 1997 + -6:00 Nic C%sT + ++# Cayman Is + # Panama ++# ++# Atikokan and Coral Harbour, Canada, match Panama since 1970. + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone America/Panama -5:18:08 - LMT 1890 + -5:19:36 - CMT 1908 Apr 22 # Colón Mean Time + -5:00 - EST +-Link America/Panama America/Atikokan +-Link America/Panama America/Cayman + ++# Anguilla ++# Antigua & Barbuda ++# Aruba ++# Caribbean Netherlands ++# Curaçao ++# Dominica ++# Grenada ++# Guadeloupe ++# Montserrat + # Puerto Rico ++# St Barthélemy ++# St Kitts-Nevis ++# Sint Maarten / St Martin ++# St Lucia ++# St Vincent & the Grenadines ++# Trinidad & Tobago ++# Virgin Is (UK & US) ++# + # There are too many San Juans elsewhere, so we'll use 'Puerto_Rico'. + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12:00 # San Juan + -4:00 - AST 1942 May 3 + -4:00 US A%sT 1946 + -4:00 - AST +-Link America/Puerto_Rico America/Anguilla +-Link America/Puerto_Rico America/Antigua +-Link America/Puerto_Rico America/Aruba +-Link America/Puerto_Rico America/Curacao +-Link America/Puerto_Rico America/Blanc-Sablon # Quebec (Lower North Shore) +-Link America/Puerto_Rico America/Dominica +-Link America/Puerto_Rico America/Grenada +-Link America/Puerto_Rico America/Guadeloupe +-Link America/Puerto_Rico America/Kralendijk # Caribbean Netherlands +-Link America/Puerto_Rico America/Lower_Princes # Sint Maarten +-Link America/Puerto_Rico America/Marigot # St Martin (French part) +-Link America/Puerto_Rico America/Montserrat +-Link America/Puerto_Rico America/Port_of_Spain # Trinidad & Tobago +-Link America/Puerto_Rico America/St_Barthelemy # St Barthélemy +-Link America/Puerto_Rico America/St_Kitts # St Kitts & Nevis +-Link America/Puerto_Rico America/St_Lucia +-Link America/Puerto_Rico America/St_Thomas # Virgin Islands (US) +-Link America/Puerto_Rico America/St_Vincent +-Link America/Puerto_Rico America/Tortola # Virgin Islands (UK) +- +-# St Kitts-Nevis +-# St Lucia +-# See America/Puerto_Rico. + + # St Pierre and Miquelon + # There are too many St Pierres elsewhere, so we'll use 'Miquelon'. +@@ -3627,12 +3545,6 @@ Zone America/Miquelon -3:44:40 - LMT 1911 May 15 # St Pierre + -3:00 - -03 1987 + -3:00 Canada -03/-02 + +-# St Vincent and the Grenadines +-# See America/Puerto_Rico. +- +-# Sint Maarten +-# See America/Puerto_Rico. +- + # Turks and Caicos + # + # From Chris Dunn in +@@ -3702,11 +3614,6 @@ Zone America/Grand_Turk -4:44:32 - LMT 1890 + -4:00 - AST 2018 Mar 11 3:00 + -5:00 US E%sT + +-# British Virgin Is +-# US Virgin Is +-# See America/Puerto_Rico. +- +- + # Local Variables: + # coding: utf-8 + # End: +diff --git a/jdk/make/data/tzdata/southamerica b/jdk/make/data/tzdata/southamerica +index 3c0e0e2..982ad09 100644 +--- a/jdk/make/data/tzdata/southamerica ++++ b/jdk/make/data/tzdata/southamerica +@@ -608,9 +608,6 @@ Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31 + -3:00 Arg -03/-02 2008 Oct 18 + -3:00 - -03 + +-# Aruba +-# See America/Puerto_Rico. +- + # Bolivia + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone America/La_Paz -4:32:36 - LMT 1890 +@@ -1455,15 +1452,6 @@ Zone America/Bogota -4:56:16 - LMT 1884 Mar 13 + # Malpelo, Providencia, San Andres + # no information; probably like America/Bogota + +-# Curaçao +-# See America/Puerto_Rico. +-# +-# From Arthur David Olson (2011-06-15): +-# use links for places with new iso3166 codes. +-# The name "Lower Prince's Quarter" is both longer than fourteen characters +-# and contains an apostrophe; use "Lower_Princes".... +-# From Paul Eggert (2021-09-29): +-# These backward-compatibility links now are in the 'northamerica' file. + + # Ecuador + # +@@ -1779,9 +1767,6 @@ Zone America/Paramaribo -3:40:40 - LMT 1911 + -3:30 - -0330 1984 Oct + -3:00 - -03 + +-# Trinidad and Tobago +-# See America/Puerto_Rico. +- + # Uruguay + # From Paul Eggert (1993-11-18): + # Uruguay wins the prize for the strangest peacetime manipulation of the rules. +diff --git a/jdk/make/data/tzdata/zone.tab b/jdk/make/data/tzdata/zone.tab +index ee02519..535d1c9 100644 +--- a/jdk/make/data/tzdata/zone.tab ++++ b/jdk/make/data/tzdata/zone.tab +@@ -137,13 +137,10 @@ CA +4606-06447 America/Moncton Atlantic - New Brunswick + CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) + CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) + CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) +-CA +4901-08816 America/Nipigon Eastern - ON, QC (no DST 1967-73) +-CA +4823-08915 America/Thunder_Bay Eastern - ON (Thunder Bay) + CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) + CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) + CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) + CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +-CA +4843-09434 America/Rainy_River Central - ON (Rainy R, Ft Frances) + CA +744144-0944945 America/Resolute Central - NU (Resolute) + CA +624900-0920459 America/Rankin_Inlet Central - NU (central) + CA +5024-10439 America/Regina CST - SK (most areas) +diff --git a/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java b/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java +index 215ad9f..d327baf 100644 +--- a/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java ++++ b/jdk/src/share/classes/sun/util/resources/TimeZoneNames.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1996, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -429,7 +429,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { + "French Guiana Summer Time", "GFST", + "French Guiana Time", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -518,7 +518,7 @@ public final class TimeZoneNames extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"Suriname Time", "SRT", +diff --git a/jdk/src/share/classes/sun/util/resources/de/TimeZoneNames_de.java b/jdk/src/share/classes/sun/util/resources/de/TimeZoneNames_de.java +index 00e490e..75d4213 100644 +--- a/jdk/src/share/classes/sun/util/resources/de/TimeZoneNames_de.java ++++ b/jdk/src/share/classes/sun/util/resources/de/TimeZoneNames_de.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -427,7 +427,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { + "Franz\u00f6sisch-Guiana Sommerzeit", "GFST", + "Franz\u00F6sisch-Guiana Zeit", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -516,7 +516,7 @@ public final class TimeZoneNames_de extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"Suriname Zeit", "SRT", +diff --git a/jdk/src/share/classes/sun/util/resources/es/TimeZoneNames_es.java b/jdk/src/share/classes/sun/util/resources/es/TimeZoneNames_es.java +index aaaf4ec..97576bf 100644 +--- a/jdk/src/share/classes/sun/util/resources/es/TimeZoneNames_es.java ++++ b/jdk/src/share/classes/sun/util/resources/es/TimeZoneNames_es.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -427,7 +427,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { + "Hora de verano de la Guayana Francesa", "GFST", + "Hora de la Guayana Francesa", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -516,7 +516,7 @@ public final class TimeZoneNames_es extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"Hora de Surinam", "SRT", +diff --git a/jdk/src/share/classes/sun/util/resources/fr/TimeZoneNames_fr.java b/jdk/src/share/classes/sun/util/resources/fr/TimeZoneNames_fr.java +index 6415066..bcf05e9 100644 +--- a/jdk/src/share/classes/sun/util/resources/fr/TimeZoneNames_fr.java ++++ b/jdk/src/share/classes/sun/util/resources/fr/TimeZoneNames_fr.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -427,7 +427,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { + "Heure d'\u00e9t\u00e9 de Guyane fran\u00e7aise", "GFST", + "Heure de Guyane fran\u00E7aise", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -516,7 +516,7 @@ public final class TimeZoneNames_fr extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"Heure du Surinam", "SRT", +diff --git a/jdk/src/share/classes/sun/util/resources/it/TimeZoneNames_it.java b/jdk/src/share/classes/sun/util/resources/it/TimeZoneNames_it.java +index dead599..951779d 100644 +--- a/jdk/src/share/classes/sun/util/resources/it/TimeZoneNames_it.java ++++ b/jdk/src/share/classes/sun/util/resources/it/TimeZoneNames_it.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -427,7 +427,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { + "Ora estiva della Guyana Francese", "GFST", + "Ora della Guyana Francese", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -516,7 +516,7 @@ public final class TimeZoneNames_it extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"Ora di Suriname", "SRT", +diff --git a/jdk/src/share/classes/sun/util/resources/ja/TimeZoneNames_ja.java b/jdk/src/share/classes/sun/util/resources/ja/TimeZoneNames_ja.java +index 0c104b5..c1dce59 100644 +--- a/jdk/src/share/classes/sun/util/resources/ja/TimeZoneNames_ja.java ++++ b/jdk/src/share/classes/sun/util/resources/ja/TimeZoneNames_ja.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -427,7 +427,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { + "\u4ecf\u9818\u30ae\u30a2\u30ca\u590f\u6642\u9593", "GFST", + "\u30D5\u30E9\u30F3\u30B9\u9818\u30AE\u30A2\u30CA\u6642\u9593", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -516,7 +516,7 @@ public final class TimeZoneNames_ja extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"\u30b9\u30ea\u30ca\u30e0\u6642\u9593", "SRT", +diff --git a/jdk/src/share/classes/sun/util/resources/ko/TimeZoneNames_ko.java b/jdk/src/share/classes/sun/util/resources/ko/TimeZoneNames_ko.java +index 65efcf5..77cf2c4 100644 +--- a/jdk/src/share/classes/sun/util/resources/ko/TimeZoneNames_ko.java ++++ b/jdk/src/share/classes/sun/util/resources/ko/TimeZoneNames_ko.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -427,7 +427,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { + "\ud504\ub791\uc2a4\ub839 \uae30\uc544\ub098 \uc77c\uad11\uc808\uc57d\uc2dc\uac04", "GFST", + "\uD504\uB791\uC2A4\uB839 \uAE30\uC544\uB098 \uD45C\uC900\uC2DC", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -516,7 +516,7 @@ public final class TimeZoneNames_ko extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"\uc218\ub9ac\ub0a8 \uc2dc\uac04", "SRT", +diff --git a/jdk/src/share/classes/sun/util/resources/pt/TimeZoneNames_pt_BR.java b/jdk/src/share/classes/sun/util/resources/pt/TimeZoneNames_pt_BR.java +index b5f3acb..9b35f2b 100644 +--- a/jdk/src/share/classes/sun/util/resources/pt/TimeZoneNames_pt_BR.java ++++ b/jdk/src/share/classes/sun/util/resources/pt/TimeZoneNames_pt_BR.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -427,7 +427,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { + "Fuso hor\u00e1rio de ver\u00e3o da Guiana Francesa", "GFST", + "Hor\u00E1rio da Guiana Francesa", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -516,7 +516,7 @@ public final class TimeZoneNames_pt_BR extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"Fuso hor\u00e1rio do Suriname", "SRT", +diff --git a/jdk/src/share/classes/sun/util/resources/sv/TimeZoneNames_sv.java b/jdk/src/share/classes/sun/util/resources/sv/TimeZoneNames_sv.java +index d51762c..0e5be03 100644 +--- a/jdk/src/share/classes/sun/util/resources/sv/TimeZoneNames_sv.java ++++ b/jdk/src/share/classes/sun/util/resources/sv/TimeZoneNames_sv.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -427,7 +427,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { + "Franska Guyana, sommartid", "GFST", + "Franska Guyana-tid", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -516,7 +516,7 @@ public final class TimeZoneNames_sv extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"Surinam, normaltid", "SRT", +diff --git a/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_CN.java b/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_CN.java +index 1c4eef0..c7946f3 100644 +--- a/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_CN.java ++++ b/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_CN.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -427,7 +427,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { + "\u6cd5\u5c5e\u572d\u4e9a\u90a3\u590f\u4ee4\u65f6", "GFST", + "\u6CD5\u5C5E\u572D\u4E9A\u90A3\u65F6\u95F4", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -516,7 +516,7 @@ public final class TimeZoneNames_zh_CN extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"\u82cf\u5229\u5357\u65f6\u95f4", "SRT", +diff --git a/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_TW.java b/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_TW.java +index f83e2b8..cbc9e75 100644 +--- a/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_TW.java ++++ b/jdk/src/share/classes/sun/util/resources/zh/TimeZoneNames_zh_TW.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -427,7 +427,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { + "\u6cd5\u5c6c\u572d\u4e9e\u90a3\u590f\u4ee4\u6642\u9593", "GFST", + "\u6CD5\u5C6C\u572D\u4E9E\u90A3\u6642\u9593", "GFT"}}, + {"America/Cayman", EST}, +- {"America/Chihuahua", MST}, ++ {"America/Chihuahua", CST}, + {"America/Creston", MST}, + {"America/Coral_Harbour", EST}, + {"America/Cordoba", AGT}, +@@ -516,7 +516,7 @@ public final class TimeZoneNames_zh_TW extends TimeZoneNamesBundle { + {"America/North_Dakota/Center", CST}, + {"America/North_Dakota/New_Salem", CST}, + {"America/Nuuk", WGT}, +- {"America/Ojinaga", MST}, ++ {"America/Ojinaga", CST}, + {"America/Panama", EST}, + {"America/Pangnirtung", EST}, + {"America/Paramaribo", new String[] {"\u8607\u5229\u5357\u6642\u9593", "SRT", +diff --git a/jdk/test/java/util/TimeZone/TimeZoneData/VERSION b/jdk/test/java/util/TimeZone/TimeZoneData/VERSION +index 0cad939..f29d2d9 100644 +--- a/jdk/test/java/util/TimeZone/TimeZoneData/VERSION ++++ b/jdk/test/java/util/TimeZone/TimeZoneData/VERSION +@@ -1 +1 @@ +-tzdata2022e ++tzdata2022f +diff --git a/jdk/test/java/util/TimeZone/TimeZoneData/aliases.txt b/jdk/test/java/util/TimeZone/TimeZoneData/aliases.txt +index e3ce742..24cec5a 100644 +--- a/jdk/test/java/util/TimeZone/TimeZoneData/aliases.txt ++++ b/jdk/test/java/util/TimeZone/TimeZoneData/aliases.txt +@@ -1,158 +1,7 @@ +-Link Africa/Abidjan Africa/Accra # Ghana +-Link Africa/Abidjan Africa/Bamako # Mali +-Link Africa/Abidjan Africa/Banjul # The Gambia +-Link Africa/Abidjan Africa/Conakry # Guinea +-Link Africa/Abidjan Africa/Dakar # Senegal +-Link Africa/Abidjan Africa/Freetown # Sierra Leone +-Link Africa/Abidjan Africa/Lome # Togo +-Link Africa/Abidjan Africa/Nouakchott # Mauritania +-Link Africa/Abidjan Africa/Ouagadougou # Burkina Faso +-Link Africa/Abidjan Atlantic/Reykjavik # Iceland +-Link Africa/Abidjan Atlantic/St_Helena # St Helena +-Link Africa/Nairobi Africa/Addis_Ababa # Ethiopia +-Link Africa/Nairobi Africa/Asmara # Eritrea +-Link Africa/Nairobi Africa/Dar_es_Salaam # Tanzania +-Link Africa/Nairobi Africa/Djibouti +-Link Africa/Nairobi Africa/Kampala # Uganda +-Link Africa/Nairobi Africa/Mogadishu # Somalia +-Link Africa/Nairobi Indian/Antananarivo # Madagascar +-Link Africa/Nairobi Indian/Comoro +-Link Africa/Nairobi Indian/Mayotte +-Link Africa/Maputo Africa/Blantyre # Malawi +-Link Africa/Maputo Africa/Bujumbura # Burundi +-Link Africa/Maputo Africa/Gaborone # Botswana +-Link Africa/Maputo Africa/Harare # Zimbabwe +-Link Africa/Maputo Africa/Kigali # Rwanda +-Link Africa/Maputo Africa/Lubumbashi # E Dem. Rep. of Congo +-Link Africa/Maputo Africa/Lusaka # Zambia +-Link Africa/Lagos Africa/Bangui # Central African Republic +-Link Africa/Lagos Africa/Brazzaville # Rep. of the Congo +-Link Africa/Lagos Africa/Douala # Cameroon +-Link Africa/Lagos Africa/Kinshasa # Dem. Rep. of the Congo (west) +-Link Africa/Lagos Africa/Libreville # Gabon +-Link Africa/Lagos Africa/Luanda # Angola +-Link Africa/Lagos Africa/Malabo # Equatorial Guinea +-Link Africa/Lagos Africa/Niamey # Niger +-Link Africa/Lagos Africa/Porto-Novo # Benin +-Link Africa/Johannesburg Africa/Maseru # Lesotho +-Link Africa/Johannesburg Africa/Mbabane # Eswatini +-Link Asia/Yangon Indian/Cocos +-Link Asia/Urumqi Antarctica/Vostok +-Link Asia/Nicosia Europe/Nicosia +-Link Asia/Kuching Asia/Brunei +-Link Indian/Maldives Indian/Kerguelen +-Link Asia/Qatar Asia/Bahrain +-Link Asia/Riyadh Antarctica/Syowa +-Link Asia/Riyadh Asia/Aden # Yemen +-Link Asia/Riyadh Asia/Kuwait +-Link Asia/Singapore Asia/Kuala_Lumpur +-Link Asia/Bangkok Asia/Phnom_Penh # Cambodia +-Link Asia/Bangkok Asia/Vientiane # Laos +-Link Asia/Bangkok Indian/Christmas +-Link Asia/Dubai Asia/Muscat # Oman +-Link Asia/Dubai Indian/Mahe +-Link Asia/Dubai Indian/Reunion +-Link Pacific/Guam Pacific/Saipan # N Mariana Is +-Link Pacific/Tarawa Pacific/Funafuti +-Link Pacific/Tarawa Pacific/Majuro +-Link Pacific/Tarawa Pacific/Wake +-Link Pacific/Tarawa Pacific/Wallis +-Link Pacific/Auckland Antarctica/McMurdo +-Link Pacific/Port_Moresby Antarctica/DumontDUrville +-Link Pacific/Port_Moresby Pacific/Chuuk +-Link Pacific/Pago_Pago Pacific/Midway # in US minor outlying islands +-Link Pacific/Guadalcanal Pacific/Pohnpei +-Link Europe/London Europe/Jersey +-Link Europe/London Europe/Guernsey +-Link Europe/London Europe/Isle_of_Man +-Link Europe/Brussels Europe/Amsterdam +-Link Europe/Brussels Europe/Luxembourg +-Link Europe/Prague Europe/Bratislava +-Link Europe/Helsinki Europe/Mariehamn +-Link Europe/Paris Europe/Monaco +-Link Europe/Berlin Arctic/Longyearbyen +-Link Europe/Berlin Europe/Copenhagen +-Link Europe/Berlin Europe/Oslo +-Link Europe/Berlin Europe/Stockholm +-Link Europe/Rome Europe/Vatican +-Link Europe/Rome Europe/San_Marino +-Link Europe/Belgrade Europe/Ljubljana # Slovenia +-Link Europe/Belgrade Europe/Podgorica # Montenegro +-Link Europe/Belgrade Europe/Sarajevo # Bosnia and Herzegovina +-Link Europe/Belgrade Europe/Skopje # North Macedonia +-Link Europe/Belgrade Europe/Zagreb # Croatia +-Link Europe/Zurich Europe/Busingen +-Link Europe/Zurich Europe/Vaduz +-Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. +-Link America/Phoenix America/Creston +-Link America/Toronto America/Nassau +-Link America/Panama America/Atikokan +-Link America/Panama America/Cayman +-Link America/Puerto_Rico America/Anguilla +-Link America/Puerto_Rico America/Antigua +-Link America/Puerto_Rico America/Aruba +-Link America/Puerto_Rico America/Curacao +-Link America/Puerto_Rico America/Blanc-Sablon # Quebec (Lower North Shore) +-Link America/Puerto_Rico America/Dominica +-Link America/Puerto_Rico America/Grenada +-Link America/Puerto_Rico America/Guadeloupe +-Link America/Puerto_Rico America/Kralendijk # Caribbean Netherlands +-Link America/Puerto_Rico America/Lower_Princes # Sint Maarten +-Link America/Puerto_Rico America/Marigot # St Martin (French part) +-Link America/Puerto_Rico America/Montserrat +-Link America/Puerto_Rico America/Port_of_Spain # Trinidad & Tobago +-Link America/Puerto_Rico America/St_Barthelemy # St Barthélemy +-Link America/Puerto_Rico America/St_Kitts # St Kitts & Nevis +-Link America/Puerto_Rico America/St_Lucia +-Link America/Puerto_Rico America/St_Thomas # Virgin Islands (US) +-Link America/Puerto_Rico America/St_Vincent +-Link America/Puerto_Rico America/Tortola # Virgin Islands (UK) + Link Asia/Riyadh87 Mideast/Riyadh87 + Link Asia/Riyadh88 Mideast/Riyadh88 + Link Asia/Riyadh89 Mideast/Riyadh89 +-Link Africa/Nairobi Africa/Asmera +-Link Africa/Abidjan Africa/Timbuktu +-Link America/Argentina/Catamarca America/Argentina/ComodRivadavia +-Link America/Adak America/Atka +-Link America/Argentina/Buenos_Aires America/Buenos_Aires +-Link America/Argentina/Catamarca America/Catamarca +-Link America/Panama America/Coral_Harbour +-Link America/Argentina/Cordoba America/Cordoba +-Link America/Tijuana America/Ensenada +-Link America/Indiana/Indianapolis America/Fort_Wayne +-Link America/Nuuk America/Godthab +-Link America/Indiana/Indianapolis America/Indianapolis +-Link America/Argentina/Jujuy America/Jujuy +-Link America/Indiana/Knox America/Knox_IN +-Link America/Kentucky/Louisville America/Louisville +-Link America/Argentina/Mendoza America/Mendoza +-Link America/Toronto America/Montreal +-Link America/Rio_Branco America/Porto_Acre +-Link America/Argentina/Cordoba America/Rosario +-Link America/Tijuana America/Santa_Isabel +-Link America/Denver America/Shiprock +-Link America/Puerto_Rico America/Virgin +-Link Pacific/Auckland Antarctica/South_Pole +-Link Asia/Ashgabat Asia/Ashkhabad +-Link Asia/Kolkata Asia/Calcutta +-Link Asia/Shanghai Asia/Chongqing +-Link Asia/Shanghai Asia/Chungking +-Link Asia/Dhaka Asia/Dacca +-Link Asia/Shanghai Asia/Harbin +-Link Asia/Urumqi Asia/Kashgar +-Link Asia/Kathmandu Asia/Katmandu +-Link Asia/Macau Asia/Macao +-Link Asia/Yangon Asia/Rangoon +-Link Asia/Ho_Chi_Minh Asia/Saigon +-Link Asia/Jerusalem Asia/Tel_Aviv +-Link Asia/Thimphu Asia/Thimbu +-Link Asia/Makassar Asia/Ujung_Pandang +-Link Asia/Ulaanbaatar Asia/Ulan_Bator +-Link Atlantic/Faroe Atlantic/Faeroe +-Link Europe/Berlin Atlantic/Jan_Mayen +-Link Australia/Sydney Australia/ACT +-Link Australia/Sydney Australia/Canberra +-Link Australia/Hobart Australia/Currie ++Link Australia/Sydney Australia/ACT #= Australia/Canberra + Link Australia/Lord_Howe Australia/LHI + Link Australia/Sydney Australia/NSW + Link Australia/Darwin Australia/North +@@ -162,7 +11,7 @@ Link Australia/Hobart Australia/Tasmania + Link Australia/Melbourne Australia/Victoria + Link Australia/Perth Australia/West + Link Australia/Broken_Hill Australia/Yancowinna +-Link America/Rio_Branco Brazil/Acre ++Link America/Rio_Branco Brazil/Acre #= America/Porto_Acre + Link America/Noronha Brazil/DeNoronha + Link America/Sao_Paulo Brazil/East + Link America/Manaus Brazil/West +@@ -179,12 +28,13 @@ Link Pacific/Easter Chile/EasterIsland + Link America/Havana Cuba + Link Africa/Cairo Egypt + Link Europe/Dublin Eire ++Link Etc/GMT Etc/GMT+0 ++Link Etc/GMT Etc/GMT-0 ++Link Etc/GMT Etc/GMT0 ++Link Etc/GMT Etc/Greenwich + Link Etc/UTC Etc/UCT +-Link Europe/London Europe/Belfast +-Link Europe/Kyiv Europe/Kiev +-Link Europe/Chisinau Europe/Tiraspol +-Link Europe/Kyiv Europe/Uzhgorod +-Link Europe/Kyiv Europe/Zaporozhye ++Link Etc/UTC Etc/Universal ++Link Etc/UTC Etc/Zulu + Link Europe/London GB + Link Europe/London GB-Eire + Link Etc/GMT GMT+0 +@@ -192,7 +42,7 @@ Link Etc/GMT GMT-0 + Link Etc/GMT GMT0 + Link Etc/GMT Greenwich + Link Asia/Hong_Kong Hongkong +-Link Africa/Abidjan Iceland ++Link Africa/Abidjan Iceland #= Atlantic/Reykjavik + Link Asia/Tehran Iran + Link Asia/Jerusalem Israel + Link America/Jamaica Jamaica +@@ -204,14 +54,8 @@ Link America/Mazatlan Mexico/BajaSur + Link America/Mexico_City Mexico/General + Link Pacific/Auckland NZ + Link Pacific/Chatham NZ-CHAT +-Link America/Denver Navajo ++Link America/Denver Navajo #= America/Shiprock + Link Asia/Shanghai PRC +-Link Pacific/Kanton Pacific/Enderbury +-Link Pacific/Honolulu Pacific/Johnston +-Link Pacific/Guadalcanal Pacific/Ponape +-Link Pacific/Pago_Pago Pacific/Samoa +-Link Pacific/Port_Moresby Pacific/Truk +-Link Pacific/Port_Moresby Pacific/Yap + Link Europe/Warsaw Poland + Link Europe/Lisbon Portugal + Link Asia/Taipei ROC +@@ -235,3 +79,168 @@ Link Etc/UTC UTC + Link Etc/UTC Universal + Link Europe/Moscow W-SU + Link Etc/UTC Zulu ++Link America/Argentina/Buenos_Aires America/Buenos_Aires ++Link America/Argentina/Catamarca America/Catamarca ++Link America/Argentina/Cordoba America/Cordoba ++Link America/Indiana/Indianapolis America/Indianapolis ++Link America/Argentina/Jujuy America/Jujuy ++Link America/Indiana/Knox America/Knox_IN ++Link America/Kentucky/Louisville America/Louisville ++Link America/Argentina/Mendoza America/Mendoza ++Link America/Puerto_Rico America/Virgin #= America/St_Thomas ++Link Pacific/Pago_Pago Pacific/Samoa ++Link Africa/Abidjan Africa/Accra ++Link Africa/Nairobi Africa/Addis_Ababa ++Link Africa/Nairobi Africa/Asmara ++Link Africa/Abidjan Africa/Bamako ++Link Africa/Lagos Africa/Bangui ++Link Africa/Abidjan Africa/Banjul ++Link Africa/Maputo Africa/Blantyre ++Link Africa/Lagos Africa/Brazzaville ++Link Africa/Maputo Africa/Bujumbura ++Link Africa/Abidjan Africa/Conakry ++Link Africa/Abidjan Africa/Dakar ++Link Africa/Nairobi Africa/Dar_es_Salaam ++Link Africa/Nairobi Africa/Djibouti ++Link Africa/Lagos Africa/Douala ++Link Africa/Abidjan Africa/Freetown ++Link Africa/Maputo Africa/Gaborone ++Link Africa/Maputo Africa/Harare ++Link Africa/Nairobi Africa/Kampala ++Link Africa/Maputo Africa/Kigali ++Link Africa/Lagos Africa/Kinshasa ++Link Africa/Lagos Africa/Libreville ++Link Africa/Abidjan Africa/Lome ++Link Africa/Lagos Africa/Luanda ++Link Africa/Maputo Africa/Lubumbashi ++Link Africa/Maputo Africa/Lusaka ++Link Africa/Lagos Africa/Malabo ++Link Africa/Johannesburg Africa/Maseru ++Link Africa/Johannesburg Africa/Mbabane ++Link Africa/Nairobi Africa/Mogadishu ++Link Africa/Lagos Africa/Niamey ++Link Africa/Abidjan Africa/Nouakchott ++Link Africa/Abidjan Africa/Ouagadougou ++Link Africa/Lagos Africa/Porto-Novo ++Link America/Puerto_Rico America/Anguilla ++Link America/Puerto_Rico America/Antigua ++Link America/Puerto_Rico America/Aruba ++Link America/Panama America/Atikokan ++Link America/Puerto_Rico America/Blanc-Sablon ++Link America/Panama America/Cayman ++Link America/Phoenix America/Creston ++Link America/Puerto_Rico America/Curacao ++Link America/Puerto_Rico America/Dominica ++Link America/Puerto_Rico America/Grenada ++Link America/Puerto_Rico America/Guadeloupe ++Link America/Puerto_Rico America/Kralendijk ++Link America/Puerto_Rico America/Lower_Princes ++Link America/Puerto_Rico America/Marigot ++Link America/Puerto_Rico America/Montserrat ++Link America/Toronto America/Nassau ++Link America/Puerto_Rico America/Port_of_Spain ++Link America/Puerto_Rico America/St_Barthelemy ++Link America/Puerto_Rico America/St_Kitts ++Link America/Puerto_Rico America/St_Lucia ++Link America/Puerto_Rico America/St_Thomas ++Link America/Puerto_Rico America/St_Vincent ++Link America/Puerto_Rico America/Tortola ++Link Pacific/Port_Moresby Antarctica/DumontDUrville ++Link Pacific/Auckland Antarctica/McMurdo ++Link Asia/Riyadh Antarctica/Syowa ++Link Asia/Urumqi Antarctica/Vostok ++Link Europe/Berlin Arctic/Longyearbyen ++Link Asia/Riyadh Asia/Aden ++Link Asia/Qatar Asia/Bahrain ++Link Asia/Kuching Asia/Brunei ++Link Asia/Singapore Asia/Kuala_Lumpur ++Link Asia/Riyadh Asia/Kuwait ++Link Asia/Dubai Asia/Muscat ++Link Asia/Bangkok Asia/Phnom_Penh ++Link Asia/Bangkok Asia/Vientiane ++Link Africa/Abidjan Atlantic/Reykjavik ++Link Africa/Abidjan Atlantic/St_Helena ++Link Europe/Brussels Europe/Amsterdam ++Link Europe/Prague Europe/Bratislava ++Link Europe/Zurich Europe/Busingen ++Link Europe/Berlin Europe/Copenhagen ++Link Europe/London Europe/Guernsey ++Link Europe/London Europe/Isle_of_Man ++Link Europe/London Europe/Jersey ++Link Europe/Belgrade Europe/Ljubljana ++Link Europe/Brussels Europe/Luxembourg ++Link Europe/Helsinki Europe/Mariehamn ++Link Europe/Paris Europe/Monaco ++Link Europe/Berlin Europe/Oslo ++Link Europe/Belgrade Europe/Podgorica ++Link Europe/Rome Europe/San_Marino ++Link Europe/Belgrade Europe/Sarajevo ++Link Europe/Belgrade Europe/Skopje ++Link Europe/Berlin Europe/Stockholm ++Link Europe/Zurich Europe/Vaduz ++Link Europe/Rome Europe/Vatican ++Link Europe/Belgrade Europe/Zagreb ++Link Africa/Nairobi Indian/Antananarivo ++Link Asia/Bangkok Indian/Christmas ++Link Asia/Yangon Indian/Cocos ++Link Africa/Nairobi Indian/Comoro ++Link Indian/Maldives Indian/Kerguelen ++Link Asia/Dubai Indian/Mahe ++Link Africa/Nairobi Indian/Mayotte ++Link Asia/Dubai Indian/Reunion ++Link Pacific/Port_Moresby Pacific/Chuuk ++Link Pacific/Tarawa Pacific/Funafuti ++Link Pacific/Tarawa Pacific/Majuro ++Link Pacific/Pago_Pago Pacific/Midway ++Link Pacific/Guadalcanal Pacific/Pohnpei ++Link Pacific/Guam Pacific/Saipan ++Link Pacific/Tarawa Pacific/Wake ++Link Pacific/Tarawa Pacific/Wallis ++Link Africa/Abidjan Africa/Timbuktu ++Link America/Argentina/Catamarca America/Argentina/ComodRivadavia ++Link America/Adak America/Atka ++Link America/Panama America/Coral_Harbour ++Link America/Tijuana America/Ensenada ++Link America/Indiana/Indianapolis America/Fort_Wayne ++Link America/Toronto America/Montreal ++Link America/Toronto America/Nipigon ++Link America/Rio_Branco America/Porto_Acre ++Link America/Winnipeg America/Rainy_River ++Link America/Argentina/Cordoba America/Rosario ++Link America/Tijuana America/Santa_Isabel ++Link America/Denver America/Shiprock ++Link America/Toronto America/Thunder_Bay ++Link Pacific/Auckland Antarctica/South_Pole ++Link Asia/Shanghai Asia/Chongqing ++Link Asia/Shanghai Asia/Harbin ++Link Asia/Urumqi Asia/Kashgar ++Link Asia/Jerusalem Asia/Tel_Aviv ++Link Europe/Berlin Atlantic/Jan_Mayen ++Link Australia/Sydney Australia/Canberra ++Link Australia/Hobart Australia/Currie ++Link Europe/London Europe/Belfast ++Link Europe/Chisinau Europe/Tiraspol ++Link Europe/Kyiv Europe/Uzhgorod ++Link Europe/Kyiv Europe/Zaporozhye ++Link Pacific/Kanton Pacific/Enderbury ++Link Pacific/Honolulu Pacific/Johnston ++Link Pacific/Port_Moresby Pacific/Yap ++Link Africa/Nairobi Africa/Asmera #= Africa/Asmara ++Link America/Nuuk America/Godthab ++Link Asia/Ashgabat Asia/Ashkhabad ++Link Asia/Kolkata Asia/Calcutta ++Link Asia/Shanghai Asia/Chungking #= Asia/Chongqing ++Link Asia/Dhaka Asia/Dacca ++Link Europe/Istanbul Asia/Istanbul ++Link Asia/Kathmandu Asia/Katmandu ++Link Asia/Macau Asia/Macao ++Link Asia/Yangon Asia/Rangoon ++Link Asia/Ho_Chi_Minh Asia/Saigon ++Link Asia/Thimphu Asia/Thimbu ++Link Asia/Makassar Asia/Ujung_Pandang ++Link Asia/Ulaanbaatar Asia/Ulan_Bator ++Link Atlantic/Faroe Atlantic/Faeroe ++Link Europe/Kyiv Europe/Kiev ++Link Asia/Nicosia Europe/Nicosia ++Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei ++Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk +diff --git a/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt b/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt +index 2f2786f..a1cd41d 100644 +--- a/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt ++++ b/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt +@@ -24,7 +24,7 @@ America/Boise MST MDT + America/Cambridge_Bay MST MDT + America/Cancun EST + America/Chicago CST CDT +-America/Chihuahua MST MDT ++America/Chihuahua CST + America/Costa_Rica CST CDT + America/Danmarkshavn GMT + America/Dawson MST +@@ -67,18 +67,16 @@ America/Mexico_City CST CDT + America/Moncton AST ADT + America/Monterrey CST CDT + America/New_York EST EDT +-America/Nipigon EST EDT + America/Nome AKST AKDT + America/North_Dakota/Beulah CST CDT + America/North_Dakota/Center CST CDT + America/North_Dakota/New_Salem CST CDT +-America/Ojinaga MST MDT ++America/Ojinaga CST + America/Panama EST + America/Pangnirtung EST EDT + America/Phoenix MST + America/Port-au-Prince EST EDT + America/Puerto_Rico AST +-America/Rainy_River CST CDT + America/Rankin_Inlet CST CDT + America/Regina CST + America/Resolute CST CDT +@@ -88,7 +86,6 @@ America/St_Johns NST NDT + America/Swift_Current CST + America/Tegucigalpa CST CDT + America/Thule AST ADT +-America/Thunder_Bay EST EDT + America/Tijuana PST PDT + America/Toronto EST EDT + America/Vancouver PST PDT +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/VERSION b/jdk/test/sun/util/calendar/zi/tzdata/VERSION +index b8cb36e..b8d9ae7 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/VERSION ++++ b/jdk/test/sun/util/calendar/zi/tzdata/VERSION +@@ -21,4 +21,4 @@ + # or visit www.oracle.com if you need additional information or have any + # questions. + # +-tzdata2022e ++tzdata2022f +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/africa b/jdk/test/sun/util/calendar/zi/tzdata/africa +index e13899b..b4559cd 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/africa ++++ b/jdk/test/sun/util/calendar/zi/tzdata/africa +@@ -120,22 +120,6 @@ Zone Africa/Algiers 0:12:12 - LMT 1891 Mar 16 + 0:00 Algeria WE%sT 1981 May + 1:00 - CET + +-# Angola +-# Benin +-# See Africa/Lagos. +- +-# Botswana +-# See Africa/Maputo. +- +-# Burkina Faso +-# See Africa/Abidjan. +- +-# Burundi +-# See Africa/Maputo. +- +-# Cameroon +-# See Africa/Lagos. +- + # Cape Verde / Cabo Verde + # + # From Paul Eggert (2018-02-16): +@@ -150,9 +134,6 @@ Zone Atlantic/Cape_Verde -1:34:04 - LMT 1912 Jan 01 2:00u # Praia + -2:00 - -02 1975 Nov 25 2:00 + -1:00 - -01 + +-# Central African Republic +-# See Africa/Lagos. +- + # Chad + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Africa/Ndjamena 1:00:12 - LMT 1912 # N'Djamena +@@ -160,33 +141,29 @@ Zone Africa/Ndjamena 1:00:12 - LMT 1912 # N'Djamena + 1:00 1:00 WAST 1980 Mar 8 + 1:00 - WAT + +-# Comoros +-# See Africa/Nairobi. +- +-# Democratic Republic of the Congo +-# See Africa/Lagos for the western part and Africa/Maputo for the eastern. ++# Burkina Faso ++# Côte d'Ivoire (Ivory Coast) ++# The Gambia ++# Ghana ++# Guinea ++# Iceland ++# Mali ++# Mauritania ++# St Helena ++# Senegal ++# Sierra Leone ++# Togo + +-# Republic of the Congo +-# See Africa/Lagos. ++# The other parts of the St Helena territory are similar: ++# Tristan da Cunha: on GMT, say Whitman and the CIA ++# Ascension: on GMT, say the USNO (1995-12-21) and the CIA ++# Gough (scientific station since 1955; sealers wintered previously): ++# on GMT, says the CIA ++# Inaccessible, Nightingale: uninhabited + +-# Côte d'Ivoire / Ivory Coast + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Africa/Abidjan -0:16:08 - LMT 1912 + 0:00 - GMT +-Link Africa/Abidjan Africa/Accra # Ghana +-Link Africa/Abidjan Africa/Bamako # Mali +-Link Africa/Abidjan Africa/Banjul # The Gambia +-Link Africa/Abidjan Africa/Conakry # Guinea +-Link Africa/Abidjan Africa/Dakar # Senegal +-Link Africa/Abidjan Africa/Freetown # Sierra Leone +-Link Africa/Abidjan Africa/Lome # Togo +-Link Africa/Abidjan Africa/Nouakchott # Mauritania +-Link Africa/Abidjan Africa/Ouagadougou # Burkina Faso +-Link Africa/Abidjan Atlantic/Reykjavik # Iceland +-Link Africa/Abidjan Atlantic/St_Helena # St Helena +- +-# Djibouti +-# See Africa/Nairobi. + + ############################################################################### + +@@ -382,33 +359,6 @@ Rule Egypt 2014 only - Sep lastThu 24:00 0 - + Zone Africa/Cairo 2:05:09 - LMT 1900 Oct + 2:00 Egypt EE%sT + +-# Equatorial Guinea +-# See Africa/Lagos. +- +-# Eritrea +-# See Africa/Nairobi. +- +-# Eswatini (formerly Swaziland) +-# See Africa/Johannesburg. +- +-# Ethiopia +-# See Africa/Nairobi. +-# +-# Unfortunately tzdb records only Western clock time in use in Ethiopia, +-# as the tzdb format is not up to properly recording a common Ethiopian +-# timekeeping practice that is based on solar time. See: +-# Mortada D. If you have a meeting in Ethiopia, you'd better double +-# check the time. PRI's The World. 2015-01-30 15:15 -05. +-# https://www.pri.org/stories/2015-01-30/if-you-have-meeting-ethiopia-you-better-double-check-time +- +-# Gabon +-# See Africa/Lagos. +- +-# The Gambia +-# Ghana +-# Guinea +-# See Africa/Abidjan. +- + # Guinea-Bissau + # + # From Paul Eggert (2018-02-16): +@@ -421,7 +371,16 @@ Zone Africa/Bissau -1:02:20 - LMT 1912 Jan 1 1:00u + -1:00 - -01 1975 + 0:00 - GMT + ++# Comoros ++# Djibouti ++# Eritrea ++# Ethiopia + # Kenya ++# Madagascar ++# Mayotte ++# Somalia ++# Tanzania ++# Uganda + + # From P Chan (2020-10-24): + # +@@ -464,6 +423,14 @@ Zone Africa/Bissau -1:02:20 - LMT 1912 Jan 1 1:00u + # The 1908-05-01 announcement does not give an effective date, + # so just say "1908 May". + ++# From Paul Eggert (2018-09-11): ++# Unfortunately tzdb records only Western clock time in use in Ethiopia, ++# as the tzdb format is not up to properly recording a common Ethiopian ++# timekeeping practice that is based on solar time. See: ++# Mortada D. If you have a meeting in Ethiopia, you'd better double ++# check the time. PRI's The World. 2015-01-30 15:15 -05. ++# https://www.pri.org/stories/2015-01-30/if-you-have-meeting-ethiopia-you-better-double-check-time ++ + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Africa/Nairobi 2:27:16 - LMT 1908 May + 2:30 - +0230 1928 Jun 30 24:00 +@@ -471,18 +438,6 @@ Zone Africa/Nairobi 2:27:16 - LMT 1908 May + 2:30 - +0230 1936 Dec 31 24:00 + 2:45 - +0245 1942 Jul 31 24:00 + 3:00 - EAT +-Link Africa/Nairobi Africa/Addis_Ababa # Ethiopia +-Link Africa/Nairobi Africa/Asmara # Eritrea +-Link Africa/Nairobi Africa/Dar_es_Salaam # Tanzania +-Link Africa/Nairobi Africa/Djibouti +-Link Africa/Nairobi Africa/Kampala # Uganda +-Link Africa/Nairobi Africa/Mogadishu # Somalia +-Link Africa/Nairobi Indian/Antananarivo # Madagascar +-Link Africa/Nairobi Indian/Comoro +-Link Africa/Nairobi Indian/Mayotte +- +-# Lesotho +-# See Africa/Johannesburg. + + # Liberia + # +@@ -563,16 +518,6 @@ Zone Africa/Tripoli 0:52:44 - LMT 1920 + 1:00 Libya CE%sT 2013 Oct 25 2:00 + 2:00 - EET + +-# Madagascar +-# See Africa/Nairobi. +- +-# Malawi +-# See Africa/Maputo. +- +-# Mali +-# Mauritania +-# See Africa/Abidjan. +- + # Mauritius + + # From Steffen Thorsen (2008-06-25): +@@ -666,12 +611,6 @@ Zone Indian/Mauritius 3:50:00 - LMT 1907 # Port Louis + # Agalega Is, Rodriguez + # no information; probably like Indian/Mauritius + +-# Mayotte +-# See Africa/Nairobi. +- +-# Morocco +-# See Africa/Ceuta for Spanish Morocco. +- + # From Alex Krivenyshev (2008-05-09): + # Here is an article that Morocco plan to introduce Daylight Saving Time between + # 1 June, 2008 and 27 September, 2008. +@@ -1160,7 +1099,14 @@ Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún + 0:00 Morocco +00/+01 2018 Oct 28 3:00 + 0:00 Morocco +00/+01 + ++# Botswana ++# Burundi ++# Democratic Republic of the Congo (eastern) ++# Malawi + # Mozambique ++# Rwanda ++# Zambia ++# Zimbabwe + # + # Shanks gives 1903-03-01 for the transition to CAT. + # Perhaps the 1911-05-26 Portuguese decree +@@ -1170,14 +1116,6 @@ Zone Africa/El_Aaiun -0:52:48 - LMT 1934 Jan # El Aaiún + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Africa/Maputo 2:10:20 - LMT 1903 Mar + 2:00 - CAT +-Link Africa/Maputo Africa/Blantyre # Malawi +-Link Africa/Maputo Africa/Bujumbura # Burundi +-Link Africa/Maputo Africa/Gaborone # Botswana +-Link Africa/Maputo Africa/Harare # Zimbabwe +-Link Africa/Maputo Africa/Kigali # Rwanda +-Link Africa/Maputo Africa/Lubumbashi # E Dem. Rep. of Congo +-Link Africa/Maputo Africa/Lusaka # Zambia +- + + # Namibia + +@@ -1256,9 +1194,16 @@ Zone Africa/Windhoek 1:08:24 - LMT 1892 Feb 8 + 2:00 - CAT + # End of rearguard section. + +-# Niger +-# See Africa/Lagos. + ++# Angola ++# Benin ++# Cameroon ++# Central African Republic ++# Democratic Republic of the Congo (western) ++# Republic of the Congo ++# Equatorial Guinea ++# Gabon ++# Niger + # Nigeria + + # From P Chan (2020-12-03): +@@ -1324,32 +1269,6 @@ Zone Africa/Lagos 0:13:35 - LMT 1905 Jul 1 + 0:13:35 - LMT 1914 Jan 1 + 0:30 - +0030 1919 Sep 1 + 1:00 - WAT +-Link Africa/Lagos Africa/Bangui # Central African Republic +-Link Africa/Lagos Africa/Brazzaville # Rep. of the Congo +-Link Africa/Lagos Africa/Douala # Cameroon +-Link Africa/Lagos Africa/Kinshasa # Dem. Rep. of the Congo (west) +-Link Africa/Lagos Africa/Libreville # Gabon +-Link Africa/Lagos Africa/Luanda # Angola +-Link Africa/Lagos Africa/Malabo # Equatorial Guinea +-Link Africa/Lagos Africa/Niamey # Niger +-Link Africa/Lagos Africa/Porto-Novo # Benin +- +-# Réunion +-# See Asia/Dubai. +-# +-# The Crozet Islands also observe Réunion time; see the 'antarctica' file. +- +-# Rwanda +-# See Africa/Maputo. +- +-# St Helena +-# See Africa/Abidjan. +-# The other parts of the St Helena territory are similar: +-# Tristan da Cunha: on GMT, say Whitman and the CIA +-# Ascension: on GMT, say the USNO (1995-12-21) and the CIA +-# Gough (scientific station since 1955; sealers wintered previously): +-# on GMT, says the CIA +-# Inaccessible, Nightingale: uninhabited + + # São Tomé and Príncipe + +@@ -1378,19 +1297,10 @@ Zone Africa/Sao_Tome 0:26:56 - LMT 1884 + 1:00 - WAT 2019 Jan 1 02:00 + 0:00 - GMT + +-# Senegal +-# See Africa/Abidjan. +- +-# Seychelles +-# See Asia/Dubai. +- +-# Sierra Leone +-# See Africa/Abidjan. +- +-# Somalia +-# See Africa/Nairobi. +- ++# Eswatini (Swaziland) ++# Lesotho + # South Africa ++ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule SA 1942 1943 - Sep Sun>=15 2:00 1:00 - + Rule SA 1943 1944 - Mar Sun>=15 2:00 0 - +@@ -1398,8 +1308,6 @@ Rule SA 1943 1944 - Mar Sun>=15 2:00 0 - + Zone Africa/Johannesburg 1:52:00 - LMT 1892 Feb 8 + 1:30 - SAST 1903 Mar + 2:00 SA SAST +-Link Africa/Johannesburg Africa/Maseru # Lesotho +-Link Africa/Johannesburg Africa/Mbabane # Eswatini + # + # Marion and Prince Edward Is + # scientific station since 1947 +@@ -1448,12 +1356,6 @@ Zone Africa/Juba 2:06:28 - LMT 1931 + 3:00 - EAT 2021 Feb 1 00:00 + 2:00 - CAT + +-# Tanzania +-# See Africa/Nairobi. +- +-# Togo +-# See Africa/Abidjan. +- + # Tunisia + + # From Gwillim Law (2005-04-30): +@@ -1551,10 +1453,3 @@ Rule Tunisia 2006 2008 - Oct lastSun 2:00s 0 - + Zone Africa/Tunis 0:40:44 - LMT 1881 May 12 + 0:09:21 - PMT 1911 Mar 11 # Paris Mean Time + 1:00 Tunisia CE%sT +- +-# Uganda +-# See Africa/Nairobi. +- +-# Zambia +-# Zimbabwe +-# See Africa/Maputo. +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/antarctica b/jdk/test/sun/util/calendar/zi/tzdata/antarctica +index 34c302e..792542b 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/antarctica ++++ b/jdk/test/sun/util/calendar/zi/tzdata/antarctica +@@ -329,4 +329,4 @@ Zone Antarctica/Rothera 0 - -00 1976 Dec 1 + # we have to go around and set them back 5 minutes or so. + # Maybe if we let them run fast all of the time, we'd get to leave here sooner!! + # +-# See 'australasia' for Antarctica/McMurdo. ++# See Pacific/Auckland. +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/asia b/jdk/test/sun/util/calendar/zi/tzdata/asia +index f1771e4..8f1fcac 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/asia ++++ b/jdk/test/sun/util/calendar/zi/tzdata/asia +@@ -172,9 +172,6 @@ Zone Asia/Baku 3:19:24 - LMT 1924 May 2 + 4:00 EUAsia +04/+05 1997 + 4:00 Azer +04/+05 + +-# Bahrain +-# See Asia/Qatar. +- + # Bangladesh + # From Alexander Krivenyshev (2009-05-13): + # According to newspaper Asian Tribune (May 6, 2009) Bangladesh may introduce +@@ -277,10 +274,8 @@ Zone Indian/Chagos 4:49:40 - LMT 1907 + 5:00 - +05 1996 + 6:00 - +06 + +-# Brunei +-# See Asia/Kuching. +- +-# Burma / Myanmar ++# Cocos (Keeling) Islands ++# Myanmar (Burma) + + # Milne says 6:24:40 was the meridian of the time ball observatory at Rangoon. + +@@ -296,11 +291,6 @@ Zone Asia/Yangon 6:24:47 - LMT 1880 # or Rangoon + 6:30 - +0630 1942 May + 9:00 - +09 1945 May 3 + 6:30 - +0630 +-Link Asia/Yangon Indian/Cocos +- +-# Cambodia +-# See Asia/Bangkok. +- + + # China + +@@ -688,10 +678,9 @@ Zone Asia/Shanghai 8:05:43 - LMT 1901 + 8:00 PRC C%sT + # Xinjiang time, used by many in western China; represented by Ürümqi / Ürümchi + # / Wulumuqi. (Please use Asia/Shanghai if you prefer Beijing time.) ++# Vostok base in Antarctica matches this since 1970. + Zone Asia/Urumqi 5:50:20 - LMT 1928 + 6:00 - +06 +-Link Asia/Urumqi Antarctica/Vostok +- + + # Hong Kong + +@@ -1195,10 +1184,6 @@ Zone Asia/Famagusta 2:15:48 - LMT 1921 Nov 14 + 3:00 - +03 2017 Oct 29 1:00u + 2:00 EUAsia EE%sT + +-# Classically, Cyprus belongs to Asia; e.g. see Herodotus, Histories, I.72. +-# However, for various reasons many users expect to find it under Europe. +-Link Asia/Nicosia Europe/Nicosia +- + # Georgia + # From Paul Eggert (1994-11-19): + # Today's _Economist_ (p 60) reports that Georgia moved its clocks forward +@@ -2727,14 +2712,6 @@ Zone Asia/Pyongyang 8:23:00 - LMT 1908 Apr 1 + 8:30 - KST 2018 May 4 23:30 + 9:00 - KST + +-############################################################################### +- +-# Kuwait +-# See Asia/Riyadh. +- +-# Laos +-# See Asia/Bangkok. +- + + # Lebanon + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S +@@ -2766,7 +2743,9 @@ Rule Lebanon 1999 max - Oct lastSun 0:00 0 - + Zone Asia/Beirut 2:22:00 - LMT 1880 + 2:00 Lebanon EE%sT + +-# Malaysia ++# Brunei ++# Malaysia (eastern) ++# + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule NBorneo 1935 1941 - Sep 14 0:00 0:20 - + Rule NBorneo 1935 1941 - Dec 14 0:00 0 - +@@ -2783,14 +2762,12 @@ Zone Asia/Kuching 7:21:20 - LMT 1926 Mar + 8:00 NBorneo +08/+0820 1942 Feb 16 + 9:00 - +09 1945 Sep 12 + 8:00 - +08 +-Link Asia/Kuching Asia/Brunei + + # Maldives + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Indian/Maldives 4:54:00 - LMT 1880 # Malé + 4:54:00 - MMT 1960 # Malé Mean Time + 5:00 - +05 +-Link Indian/Maldives Indian/Kerguelen + + # Mongolia + +@@ -2953,9 +2930,6 @@ Zone Asia/Kathmandu 5:41:16 - LMT 1920 + 5:30 - +0530 1986 + 5:45 - +0545 + +-# Oman +-# See Asia/Dubai. +- + # Pakistan + + # From Rives McDow (2002-03-13): +@@ -3566,14 +3540,18 @@ Zone Asia/Manila -15:56:00 - LMT 1844 Dec 31 + 9:00 - JST 1944 Nov + 8:00 Phil P%sT + ++# Bahrain + # Qatar + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Qatar 3:26:08 - LMT 1920 # Al Dawhah / Doha + 4:00 - +04 1972 Jun + 3:00 - +03 +-Link Asia/Qatar Asia/Bahrain + ++# Kuwait + # Saudi Arabia ++# Yemen ++# ++# Japan's year-round bases in Antarctica match this since 1970. + # + # From Paul Eggert (2018-08-29): + # Time in Saudi Arabia and other countries in the Arabian peninsula was not +@@ -3618,9 +3596,6 @@ Link Asia/Qatar Asia/Bahrain + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Riyadh 3:06:52 - LMT 1947 Mar 14 + 3:00 - +03 +-Link Asia/Riyadh Antarctica/Syowa +-Link Asia/Riyadh Asia/Aden # Yemen +-Link Asia/Riyadh Asia/Kuwait + + # Singapore + # taken from Mok Ly Yng (2003-10-30) +@@ -3635,7 +3610,6 @@ Zone Asia/Singapore 6:55:25 - LMT 1901 Jan 1 + 9:00 - +09 1945 Sep 12 + 7:30 - +0730 1982 Jan 1 + 8:00 - +08 +-Link Asia/Singapore Asia/Kuala_Lumpur + + # Spratly Is + # no information +@@ -3881,14 +3855,15 @@ Zone Asia/Dushanbe 4:35:12 - LMT 1924 May 2 + 5:00 1:00 +06 1991 Sep 9 2:00s + 5:00 - +05 + ++# Cambodia ++# Christmas I ++# Laos + # Thailand ++# Vietnam (northern) + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Bangkok 6:42:04 - LMT 1880 + 6:42:04 - BMT 1920 Apr # Bangkok Mean Time + 7:00 - +07 +-Link Asia/Bangkok Asia/Phnom_Penh # Cambodia +-Link Asia/Bangkok Asia/Vientiane # Laos +-Link Asia/Bangkok Indian/Christmas + + # Turkmenistan + # From Shanks & Pottenger. +@@ -3899,13 +3874,15 @@ Zone Asia/Ashgabat 3:53:32 - LMT 1924 May 2 # or Ashkhabad + 4:00 RussiaAsia +04/+05 1992 Jan 19 2:00 + 5:00 - +05 + ++# Oman ++# Réunion ++# Seychelles + # United Arab Emirates ++# ++# The Crozet Is also observe Réunion time; see the 'antarctica' file. + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Dubai 3:41:12 - LMT 1920 + 4:00 - +04 +-Link Asia/Dubai Asia/Muscat # Oman +-Link Asia/Dubai Indian/Mahe +-Link Asia/Dubai Indian/Reunion + + # Uzbekistan + # Byalokoz 1919 says Uzbekistan was 4:27:53. +@@ -3925,7 +3902,7 @@ Zone Asia/Tashkent 4:37:11 - LMT 1924 May 2 + 5:00 RussiaAsia +05/+06 1992 + 5:00 - +05 + +-# Vietnam ++# Vietnam (southern) + + # From Paul Eggert (2014-10-04): + # Milne gives 7:16:56 for the meridian of Saigon in 1899, as being +@@ -3999,7 +3976,3 @@ Zone Asia/Ho_Chi_Minh 7:06:30 - LMT 1906 Jul 1 + # For timestamps in north Vietnam back to 1970 (the tzdb cutoff), + # use Asia/Bangkok; see the VN entries in the file zone1970.tab. + # For timestamps before 1970, see Asia/Hanoi in the file 'backzone'. +- +- +-# Yemen +-# See Asia/Riyadh. +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/australasia b/jdk/test/sun/util/calendar/zi/tzdata/australasia +index 019cd77..fbe3b8a 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/australasia ++++ b/jdk/test/sun/util/calendar/zi/tzdata/australasia +@@ -274,13 +274,6 @@ Zone Antarctica/Macquarie 0 - -00 1899 Nov + 10:00 1:00 AEDT 2011 + 10:00 AT AE%sT + +-# Christmas +-# See Asia/Bangkok. +- +-# Cocos (Keeling) Is +-# See Asia/Yangon. +- +- + # Fiji + + # Milne gives 11:55:44 for Suva. +@@ -416,8 +409,14 @@ Zone Antarctica/Macquarie 0 - -00 1899 Nov + # concerned shifting arrival and departure times, which may look like a simple + # thing but requires some significant logistical adjustments domestically and + # internationally." +-# Assume for now that DST will resume with the recent pre-2020 rules for the +-# 2022/2023 season. ++ ++# From Shalvin Narayan (2022-10-27): ++# Please note that there will not be any daylight savings time change ++# in Fiji for 2022-2023.... ++# https://www.facebook.com/FijianGovernment/posts/pfbid0mmWVTYmTibn66ybpFda75pDcf34SSpoSaskJW5gXwaKo5Sgc7273Q4fXWc6kQV6Hl ++# ++# From Paul Eggert (2022-10-27): ++# For now, assume DST is suspended indefinitely. + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Fiji 1998 1999 - Nov Sun>=1 2:00 1:00 - +@@ -432,8 +431,6 @@ Rule Fiji 2014 2018 - Nov Sun>=1 2:00 1:00 - + Rule Fiji 2015 2021 - Jan Sun>=12 3:00 0 - + Rule Fiji 2019 only - Nov Sun>=8 2:00 1:00 - + Rule Fiji 2020 only - Dec 20 2:00 1:00 - +-Rule Fiji 2022 max - Nov Sun>=8 2:00 1:00 - +-Rule Fiji 2023 max - Jan Sun>=12 3:00 0 - + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Pacific/Fiji 11:55:44 - LMT 1915 Oct 26 # Suva + 12:00 Fiji +12/+13 +@@ -449,7 +446,9 @@ Zone Pacific/Tahiti -9:58:16 - LMT 1912 Oct # Papeete + # Clipperton (near North America) is administered from French Polynesia; + # it is uninhabited. + ++ + # Guam ++# N Mariana Is + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + # http://guamlegislature.com/Public_Laws_5th/PL05-025.pdf +@@ -489,17 +488,20 @@ Zone Pacific/Guam -14:21:00 - LMT 1844 Dec 31 + 9:00 - +09 1944 Jul 31 + 10:00 Guam G%sT 2000 Dec 23 + 10:00 - ChST # Chamorro Standard Time +-Link Pacific/Guam Pacific/Saipan # N Mariana Is + +-# Kiribati ++ ++# Kiribati (Gilbert Is) ++# Marshall Is ++# Tuvalu ++# Wake ++# Wallis & Futuna + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Pacific/Tarawa 11:32:04 - LMT 1901 # Bairiki + 12:00 - +12 +-Link Pacific/Tarawa Pacific/Funafuti +-Link Pacific/Tarawa Pacific/Majuro +-Link Pacific/Tarawa Pacific/Wake +-Link Pacific/Tarawa Pacific/Wallis + ++# Kiribati (except Gilbert Is) ++# See Pacific/Tarawa for the Gilbert Is. ++# Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Pacific/Kanton 0 - -00 1937 Aug 31 + -12:00 - -12 1979 Oct + -11:00 - -11 1994 Dec 31 +@@ -509,9 +511,6 @@ Zone Pacific/Kiritimati -10:29:20 - LMT 1901 + -10:00 - -10 1994 Dec 31 + 14:00 - +14 + +-# N Mariana Is +-# See Pacific/Guam. +- + # Marshall Is + # See Pacific/Tarawa for most locations. + # Zone NAME STDOFF RULES FORMAT [UNTIL] +@@ -561,6 +560,7 @@ Zone Pacific/Noumea 11:05:48 - LMT 1912 Jan 13 # Nouméa + ############################################################################### + + # New Zealand ++# McMurdo Station and Scott Base in Antarctica use Auckland time. + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule NZ 1927 only - Nov 6 2:00 1:00 S +@@ -596,7 +596,6 @@ Rule Chatham 2008 max - Apr Sun>=1 2:45s 0 - + Zone Pacific/Auckland 11:39:04 - LMT 1868 Nov 2 + 11:30 NZ NZ%sT 1946 Jan 1 + 12:00 NZ NZ%sT +-Link Pacific/Auckland Antarctica/McMurdo + + Zone Pacific/Chatham 12:13:48 - LMT 1868 Nov 2 + 12:15 - +1215 1946 Jan 1 +@@ -695,8 +694,6 @@ Zone Pacific/Palau -15:02:04 - LMT 1844 Dec 31 # Koror + Zone Pacific/Port_Moresby 9:48:40 - LMT 1880 + 9:48:32 - PMMT 1895 # Port Moresby Mean Time + 10:00 - +10 +-Link Pacific/Port_Moresby Antarctica/DumontDUrville +-Link Pacific/Port_Moresby Pacific/Chuuk + # + # From Paul Eggert (2014-10-13): + # Base the Bougainville entry on the Arawa-Kieta region, which appears to have +@@ -729,10 +726,10 @@ Zone Pacific/Pitcairn -8:40:20 - LMT 1901 # Adamstown + -8:00 - -08 + + # American Samoa ++# Midway + Zone Pacific/Pago_Pago 12:37:12 - LMT 1892 Jul 5 + -11:22:48 - LMT 1911 + -11:00 - SST # S=Samoa +-Link Pacific/Pago_Pago Pacific/Midway # in US minor outlying islands + + # Samoa (formerly and also known as Western Samoa) + +@@ -824,7 +821,6 @@ Zone Pacific/Apia 12:33:04 - LMT 1892 Jul 5 + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Pacific/Guadalcanal 10:39:48 - LMT 1912 Oct # Honiara + 11:00 - +11 +-Link Pacific/Guadalcanal Pacific/Pohnpei + + # Tokelau + # +@@ -864,9 +860,6 @@ Zone Pacific/Tongatapu 12:19:12 - LMT 1945 Sep 10 + 13:00 - +13 1999 + 13:00 Tonga +13/+14 + +-# Tuvalu +-# See Pacific/Tarawa. +- + + # US minor outlying islands + +@@ -917,15 +910,9 @@ Zone Pacific/Tongatapu 12:19:12 - LMT 1945 Sep 10 + # Kingman + # uninhabited + +-# Midway +-# See Pacific/Pago_Pago. +- + # Palmyra + # uninhabited since World War II; was probably like Pacific/Kiritimati + +-# Wake +-# See Pacific/Tarawa. +- + + # Vanuatu + +@@ -962,9 +949,6 @@ Rule Vanuatu 1992 only - Oct Sat>=22 24:00 1:00 - + Zone Pacific/Efate 11:13:16 - LMT 1912 Jan 13 # Vila + 11:00 Vanuatu +11/+12 + +-# Wallis and Futuna +-# See Pacific/Tarawa. +- + ############################################################################### + + # NOTES +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/backward b/jdk/test/sun/util/calendar/zi/tzdata/backward +index 7765d99..1fb087a 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/backward ++++ b/jdk/test/sun/util/calendar/zi/tzdata/backward +@@ -27,7 +27,7 @@ + # 2009-05-17 by Arthur David Olson. + + # This file provides links from old or merged timezone names to current ones. +-# Many names changed in late 1993, and many merged names moved here ++# Many names changed in 1993 and in 1995, and many merged names moved here + # in the period from 2013 through 2022. Several of these names are + # also present in the file 'backzone', which has data important only + # for pre-1970 timestamps and so is out of scope for tzdb proper. +@@ -36,50 +36,24 @@ + # building with 'make BACKWARD=', in practice downstream users + # typically use this file for backward compatibility. + +-# Link TARGET LINK-NAME +-Link Africa/Nairobi Africa/Asmera +-Link Africa/Abidjan Africa/Timbuktu +-Link America/Argentina/Catamarca America/Argentina/ComodRivadavia +-Link America/Adak America/Atka +-Link America/Argentina/Buenos_Aires America/Buenos_Aires +-Link America/Argentina/Catamarca America/Catamarca +-Link America/Panama America/Coral_Harbour +-Link America/Argentina/Cordoba America/Cordoba +-Link America/Tijuana America/Ensenada +-Link America/Indiana/Indianapolis America/Fort_Wayne +-Link America/Nuuk America/Godthab +-Link America/Indiana/Indianapolis America/Indianapolis +-Link America/Argentina/Jujuy America/Jujuy +-Link America/Indiana/Knox America/Knox_IN +-Link America/Kentucky/Louisville America/Louisville +-Link America/Argentina/Mendoza America/Mendoza +-Link America/Toronto America/Montreal +-Link America/Rio_Branco America/Porto_Acre +-Link America/Argentina/Cordoba America/Rosario +-Link America/Tijuana America/Santa_Isabel +-Link America/Denver America/Shiprock +-Link America/Puerto_Rico America/Virgin +-Link Pacific/Auckland Antarctica/South_Pole +-Link Asia/Ashgabat Asia/Ashkhabad +-Link Asia/Kolkata Asia/Calcutta +-Link Asia/Shanghai Asia/Chongqing +-Link Asia/Shanghai Asia/Chungking +-Link Asia/Dhaka Asia/Dacca +-Link Asia/Shanghai Asia/Harbin +-Link Asia/Urumqi Asia/Kashgar +-Link Asia/Kathmandu Asia/Katmandu +-Link Asia/Macau Asia/Macao +-Link Asia/Yangon Asia/Rangoon +-Link Asia/Ho_Chi_Minh Asia/Saigon +-Link Asia/Jerusalem Asia/Tel_Aviv +-Link Asia/Thimphu Asia/Thimbu +-Link Asia/Makassar Asia/Ujung_Pandang +-Link Asia/Ulaanbaatar Asia/Ulan_Bator +-Link Atlantic/Faroe Atlantic/Faeroe +-Link Europe/Berlin Atlantic/Jan_Mayen +-Link Australia/Sydney Australia/ACT +-Link Australia/Sydney Australia/Canberra +-Link Australia/Hobart Australia/Currie ++# This file is divided into sections, one for each major reason for a ++# backward compatibility link. Each section is sorted by link name. ++ ++# A "#= TARGET1" comment labels each link inserted only because some ++# .zi parsers (including tzcode through 2022e) mishandle links to links. ++# The comment says what the target would be if these parsers were fixed ++# so that data could contain links to links. For example, the line ++# "Link Australia/Sydney Australia/ACT #= Australia/Canberra" would be ++# "Link Australia/Canberra Australia/ACT" were it not that data lines ++# refrain from linking to links like Australia/Canberra, which means ++# the Australia/ACT line links instead to Australia/Sydney, ++# Australia/Canberra's target. ++ ++ ++# Pre-1993 naming conventions ++ ++# Link TARGET LINK-NAME #= TARGET1 ++Link Australia/Sydney Australia/ACT #= Australia/Canberra + Link Australia/Lord_Howe Australia/LHI + Link Australia/Sydney Australia/NSW + Link Australia/Darwin Australia/North +@@ -89,7 +63,7 @@ Link Australia/Hobart Australia/Tasmania + Link Australia/Melbourne Australia/Victoria + Link Australia/Perth Australia/West + Link Australia/Broken_Hill Australia/Yancowinna +-Link America/Rio_Branco Brazil/Acre ++Link America/Rio_Branco Brazil/Acre #= America/Porto_Acre + Link America/Noronha Brazil/DeNoronha + Link America/Sao_Paulo Brazil/East + Link America/Manaus Brazil/West +@@ -109,20 +83,36 @@ Link Pacific/Easter Chile/EasterIsland + Link America/Havana Cuba + Link Africa/Cairo Egypt + Link Europe/Dublin Eire ++# Vanguard section, for most .zi parsers. ++#Link GMT Etc/GMT ++#Link GMT Etc/GMT+0 ++#Link GMT Etc/GMT-0 ++#Link GMT Etc/GMT0 ++#Link GMT Etc/Greenwich ++# Rearguard section, for TZUpdater 2.3.2 and earlier. ++Link Etc/GMT Etc/GMT+0 ++Link Etc/GMT Etc/GMT-0 ++Link Etc/GMT Etc/GMT0 ++Link Etc/GMT Etc/Greenwich ++# End of rearguard section. + Link Etc/UTC Etc/UCT +-Link Europe/London Europe/Belfast +-Link Europe/Kyiv Europe/Kiev +-Link Europe/Chisinau Europe/Tiraspol +-Link Europe/Kyiv Europe/Uzhgorod +-Link Europe/Kyiv Europe/Zaporozhye ++Link Etc/UTC Etc/Universal ++Link Etc/UTC Etc/Zulu + Link Europe/London GB + Link Europe/London GB-Eire ++# Vanguard section, for most .zi parsers. ++#Link GMT GMT+0 ++#Link GMT GMT-0 ++#Link GMT GMT0 ++#Link GMT Greenwich ++# Rearguard section, for TZUpdater 2.3.2 and earlier. + Link Etc/GMT GMT+0 + Link Etc/GMT GMT-0 + Link Etc/GMT GMT0 + Link Etc/GMT Greenwich ++# End of rearguard section. + Link Asia/Hong_Kong Hongkong +-Link Africa/Abidjan Iceland ++Link Africa/Abidjan Iceland #= Atlantic/Reykjavik + Link Asia/Tehran Iran + Link Asia/Jerusalem Israel + Link America/Jamaica Jamaica +@@ -134,14 +124,8 @@ Link America/Mazatlan Mexico/BajaSur + Link America/Mexico_City Mexico/General + Link Pacific/Auckland NZ + Link Pacific/Chatham NZ-CHAT +-Link America/Denver Navajo ++Link America/Denver Navajo #= America/Shiprock + Link Asia/Shanghai PRC +-Link Pacific/Kanton Pacific/Enderbury +-Link Pacific/Honolulu Pacific/Johnston +-Link Pacific/Guadalcanal Pacific/Ponape +-Link Pacific/Pago_Pago Pacific/Samoa +-Link Pacific/Port_Moresby Pacific/Truk +-Link Pacific/Port_Moresby Pacific/Yap + Link Europe/Warsaw Poland + Link Europe/Lisbon Portugal + Link Asia/Taipei ROC +@@ -165,3 +149,192 @@ Link Etc/UTC UTC + Link Etc/UTC Universal + Link Europe/Moscow W-SU + Link Etc/UTC Zulu ++ ++ ++# Two-part names that were renamed mostly to three-part names in 1995 ++ ++# Link TARGET LINK-NAME #= TARGET1 ++Link America/Argentina/Buenos_Aires America/Buenos_Aires ++Link America/Argentina/Catamarca America/Catamarca ++Link America/Argentina/Cordoba America/Cordoba ++Link America/Indiana/Indianapolis America/Indianapolis ++Link America/Argentina/Jujuy America/Jujuy ++Link America/Indiana/Knox America/Knox_IN ++Link America/Kentucky/Louisville America/Louisville ++Link America/Argentina/Mendoza America/Mendoza ++Link America/Puerto_Rico America/Virgin #= America/St_Thomas ++Link Pacific/Pago_Pago Pacific/Samoa ++ ++ ++# Pre-2013 practice, which typically had a Zone per zone.tab line ++ ++# Link TARGET LINK-NAME ++Link Africa/Abidjan Africa/Accra ++Link Africa/Nairobi Africa/Addis_Ababa ++Link Africa/Nairobi Africa/Asmara ++Link Africa/Abidjan Africa/Bamako ++Link Africa/Lagos Africa/Bangui ++Link Africa/Abidjan Africa/Banjul ++Link Africa/Maputo Africa/Blantyre ++Link Africa/Lagos Africa/Brazzaville ++Link Africa/Maputo Africa/Bujumbura ++Link Africa/Abidjan Africa/Conakry ++Link Africa/Abidjan Africa/Dakar ++Link Africa/Nairobi Africa/Dar_es_Salaam ++Link Africa/Nairobi Africa/Djibouti ++Link Africa/Lagos Africa/Douala ++Link Africa/Abidjan Africa/Freetown ++Link Africa/Maputo Africa/Gaborone ++Link Africa/Maputo Africa/Harare ++Link Africa/Nairobi Africa/Kampala ++Link Africa/Maputo Africa/Kigali ++Link Africa/Lagos Africa/Kinshasa ++Link Africa/Lagos Africa/Libreville ++Link Africa/Abidjan Africa/Lome ++Link Africa/Lagos Africa/Luanda ++Link Africa/Maputo Africa/Lubumbashi ++Link Africa/Maputo Africa/Lusaka ++Link Africa/Lagos Africa/Malabo ++Link Africa/Johannesburg Africa/Maseru ++Link Africa/Johannesburg Africa/Mbabane ++Link Africa/Nairobi Africa/Mogadishu ++Link Africa/Lagos Africa/Niamey ++Link Africa/Abidjan Africa/Nouakchott ++Link Africa/Abidjan Africa/Ouagadougou ++Link Africa/Lagos Africa/Porto-Novo ++Link America/Puerto_Rico America/Anguilla ++Link America/Puerto_Rico America/Antigua ++Link America/Puerto_Rico America/Aruba ++Link America/Panama America/Atikokan ++Link America/Puerto_Rico America/Blanc-Sablon ++Link America/Panama America/Cayman ++Link America/Phoenix America/Creston ++Link America/Puerto_Rico America/Curacao ++Link America/Puerto_Rico America/Dominica ++Link America/Puerto_Rico America/Grenada ++Link America/Puerto_Rico America/Guadeloupe ++Link America/Puerto_Rico America/Kralendijk ++Link America/Puerto_Rico America/Lower_Princes ++Link America/Puerto_Rico America/Marigot ++Link America/Puerto_Rico America/Montserrat ++Link America/Toronto America/Nassau ++Link America/Puerto_Rico America/Port_of_Spain ++Link America/Puerto_Rico America/St_Barthelemy ++Link America/Puerto_Rico America/St_Kitts ++Link America/Puerto_Rico America/St_Lucia ++Link America/Puerto_Rico America/St_Thomas ++Link America/Puerto_Rico America/St_Vincent ++Link America/Puerto_Rico America/Tortola ++Link Pacific/Port_Moresby Antarctica/DumontDUrville ++Link Pacific/Auckland Antarctica/McMurdo ++Link Asia/Riyadh Antarctica/Syowa ++Link Asia/Urumqi Antarctica/Vostok ++Link Europe/Berlin Arctic/Longyearbyen ++Link Asia/Riyadh Asia/Aden ++Link Asia/Qatar Asia/Bahrain ++Link Asia/Kuching Asia/Brunei ++Link Asia/Singapore Asia/Kuala_Lumpur ++Link Asia/Riyadh Asia/Kuwait ++Link Asia/Dubai Asia/Muscat ++Link Asia/Bangkok Asia/Phnom_Penh ++Link Asia/Bangkok Asia/Vientiane ++Link Africa/Abidjan Atlantic/Reykjavik ++Link Africa/Abidjan Atlantic/St_Helena ++Link Europe/Brussels Europe/Amsterdam ++Link Europe/Prague Europe/Bratislava ++Link Europe/Zurich Europe/Busingen ++Link Europe/Berlin Europe/Copenhagen ++Link Europe/London Europe/Guernsey ++Link Europe/London Europe/Isle_of_Man ++Link Europe/London Europe/Jersey ++Link Europe/Belgrade Europe/Ljubljana ++Link Europe/Brussels Europe/Luxembourg ++Link Europe/Helsinki Europe/Mariehamn ++Link Europe/Paris Europe/Monaco ++Link Europe/Berlin Europe/Oslo ++Link Europe/Belgrade Europe/Podgorica ++Link Europe/Rome Europe/San_Marino ++Link Europe/Belgrade Europe/Sarajevo ++Link Europe/Belgrade Europe/Skopje ++Link Europe/Berlin Europe/Stockholm ++Link Europe/Zurich Europe/Vaduz ++Link Europe/Rome Europe/Vatican ++Link Europe/Belgrade Europe/Zagreb ++Link Africa/Nairobi Indian/Antananarivo ++Link Asia/Bangkok Indian/Christmas ++Link Asia/Yangon Indian/Cocos ++Link Africa/Nairobi Indian/Comoro ++Link Indian/Maldives Indian/Kerguelen ++Link Asia/Dubai Indian/Mahe ++Link Africa/Nairobi Indian/Mayotte ++Link Asia/Dubai Indian/Reunion ++Link Pacific/Port_Moresby Pacific/Chuuk ++Link Pacific/Tarawa Pacific/Funafuti ++Link Pacific/Tarawa Pacific/Majuro ++Link Pacific/Pago_Pago Pacific/Midway ++Link Pacific/Guadalcanal Pacific/Pohnpei ++Link Pacific/Guam Pacific/Saipan ++Link Pacific/Tarawa Pacific/Wake ++Link Pacific/Tarawa Pacific/Wallis ++ ++ ++# Non-zone.tab locations with timestamps since 1970 that duplicate ++# those of an existing location ++ ++# Link TARGET LINK-NAME ++Link Africa/Abidjan Africa/Timbuktu ++Link America/Argentina/Catamarca America/Argentina/ComodRivadavia ++Link America/Adak America/Atka ++Link America/Panama America/Coral_Harbour ++Link America/Tijuana America/Ensenada ++Link America/Indiana/Indianapolis America/Fort_Wayne ++Link America/Toronto America/Montreal ++Link America/Toronto America/Nipigon ++Link America/Rio_Branco America/Porto_Acre ++Link America/Winnipeg America/Rainy_River ++Link America/Argentina/Cordoba America/Rosario ++Link America/Tijuana America/Santa_Isabel ++Link America/Denver America/Shiprock ++Link America/Toronto America/Thunder_Bay ++Link Pacific/Auckland Antarctica/South_Pole ++Link Asia/Shanghai Asia/Chongqing ++Link Asia/Shanghai Asia/Harbin ++Link Asia/Urumqi Asia/Kashgar ++Link Asia/Jerusalem Asia/Tel_Aviv ++Link Europe/Berlin Atlantic/Jan_Mayen ++Link Australia/Sydney Australia/Canberra ++Link Australia/Hobart Australia/Currie ++Link Europe/London Europe/Belfast ++Link Europe/Chisinau Europe/Tiraspol ++Link Europe/Kyiv Europe/Uzhgorod ++Link Europe/Kyiv Europe/Zaporozhye ++Link Pacific/Kanton Pacific/Enderbury ++Link Pacific/Honolulu Pacific/Johnston ++Link Pacific/Port_Moresby Pacific/Yap ++ ++ ++# Alternate names for the same location ++ ++# Link TARGET LINK-NAME #= TARGET1 ++Link Africa/Nairobi Africa/Asmera #= Africa/Asmara ++Link America/Nuuk America/Godthab ++Link Asia/Ashgabat Asia/Ashkhabad ++Link Asia/Kolkata Asia/Calcutta ++Link Asia/Shanghai Asia/Chungking #= Asia/Chongqing ++Link Asia/Dhaka Asia/Dacca ++# Istanbul is in both continents. ++Link Europe/Istanbul Asia/Istanbul ++Link Asia/Kathmandu Asia/Katmandu ++Link Asia/Macau Asia/Macao ++Link Asia/Yangon Asia/Rangoon ++Link Asia/Ho_Chi_Minh Asia/Saigon ++Link Asia/Thimphu Asia/Thimbu ++Link Asia/Makassar Asia/Ujung_Pandang ++Link Asia/Ulaanbaatar Asia/Ulan_Bator ++Link Atlantic/Faroe Atlantic/Faeroe ++Link Europe/Kyiv Europe/Kiev ++# Classically, Cyprus is in Asia; e.g. see Herodotus, Histories, I.72. ++# However, for various reasons many users expect to find it under Europe. ++Link Asia/Nicosia Europe/Nicosia ++Link Pacific/Guadalcanal Pacific/Ponape #= Pacific/Pohnpei ++Link Pacific/Port_Moresby Pacific/Truk #= Pacific/Chuuk +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/etcetera b/jdk/test/sun/util/calendar/zi/tzdata/etcetera +index 82ff6b4..8ae294f 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/etcetera ++++ b/jdk/test/sun/util/calendar/zi/tzdata/etcetera +@@ -39,26 +39,23 @@ + # Do not use a POSIX TZ setting like TZ='GMT+4', which is four hours + # behind GMT but uses the completely misleading abbreviation "GMT". + +-Zone Etc/GMT 0 - GMT +- + # The following zone is used by tzcode functions like gmtime, + # which load the "UTC" file to handle seconds properly. + Zone Etc/UTC 0 - UTC + ++# Functions like gmtime load the "GMT" file to handle leap seconds properly. ++# Vanguard section, which works with most .zi parsers. ++#Zone GMT 0 - GMT ++# Rearguard section, for TZUpdater 2.3.2 and earlier. ++Zone Etc/GMT 0 - GMT ++ + # The following link uses older naming conventions, + # but it belongs here, not in the file 'backward', + # as it is needed for tzcode releases through 2022a, + # where functions like gmtime load "GMT" instead of the "Etc/UTC". + # We want this to work even on installations that omit 'backward'. + Link Etc/GMT GMT +- +-Link Etc/UTC Etc/Universal +-Link Etc/UTC Etc/Zulu +- +-Link Etc/GMT Etc/Greenwich +-Link Etc/GMT Etc/GMT-0 +-Link Etc/GMT Etc/GMT+0 +-Link Etc/GMT Etc/GMT0 ++# End of rearguard section. + + # Be consistent with POSIX TZ settings in the Zone names, + # even though this is the opposite of what many people expect. +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/europe b/jdk/test/sun/util/calendar/zi/tzdata/europe +index 930cede..7b6aa13 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/europe ++++ b/jdk/test/sun/util/calendar/zi/tzdata/europe +@@ -527,9 +527,6 @@ Zone Europe/London -0:01:15 - LMT 1847 Dec 1 + 1:00 - BST 1971 Oct 31 2:00u + 0:00 GB-Eire %s 1996 + 0:00 EU GMT/BST +-Link Europe/London Europe/Jersey +-Link Europe/London Europe/Guernsey +-Link Europe/London Europe/Isle_of_Man + + # From Paul Eggert (2018-02-15): + # In January 2018 we discovered that the negative SAVE values in the +@@ -902,6 +899,8 @@ Zone Europe/Minsk 1:50:16 - LMT 1880 + 3:00 - +03 + + # Belgium ++# Luxembourg ++# Netherlands + # + # From Michael Deckers (2019-08-25): + # The exposition in the web page +@@ -984,11 +983,6 @@ Zone Europe/Brussels 0:17:30 - LMT 1880 + 1:00 C-Eur CE%sT 1944 Sep 3 + 1:00 Belgium CE%sT 1977 + 1:00 EU CE%sT +-Link Europe/Brussels Europe/Amsterdam +-Link Europe/Brussels Europe/Luxembourg +- +-# Bosnia and Herzegovina +-# See Europe/Belgrade. + + # Bulgaria + # +@@ -1015,13 +1009,11 @@ Zone Europe/Sofia 1:33:16 - LMT 1880 + 2:00 E-Eur EE%sT 1997 + 2:00 EU EE%sT + +-# Croatia +-# See Europe/Belgrade. +- + # Cyprus + # Please see the 'asia' file for Asia/Nicosia. + +-# Czech Republic / Czechia ++# Czech Republic (Czechia) ++# Slovakia + # + # From Paul Eggert (2018-04-15): + # The source for Czech data is: Kdy začíná a končí letní čas. 2018-04-15. +@@ -1048,15 +1040,14 @@ Zone Europe/Prague 0:57:44 - LMT 1850 + # End of rearguard section. + 1:00 Czech CE%sT 1979 + 1:00 EU CE%sT +-Link Europe/Prague Europe/Bratislava +- +- +-# Denmark, Faroe Islands, and Greenland +-# For Denmark see Europe/Berlin. + ++# Faroe Is ++# Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Atlantic/Faroe -0:27:04 - LMT 1908 Jan 11 # Tórshavn + 0:00 - WET 1981 + 0:00 EU WE%sT ++ ++# Greenland + # + # From Paul Eggert (2004-10-31): + # During World War II, Germany maintained secret manned weather stations in +@@ -1282,11 +1273,8 @@ Zone Europe/Helsinki 1:39:49 - LMT 1878 May 31 + 2:00 Finland EE%sT 1983 + 2:00 EU EE%sT + +-# Åland Is +-Link Europe/Helsinki Europe/Mariehamn +- +- + # France ++# Monaco + + # From Ciro Discepolo (2000-12-20): + # +@@ -1423,9 +1411,11 @@ Zone Europe/Paris 0:09:21 - LMT 1891 Mar 16 + 0:00 France WE%sT 1945 Sep 16 3:00 + 1:00 France CE%sT 1977 + 1:00 EU CE%sT +-Link Europe/Paris Europe/Monaco + ++# Denmark + # Germany ++# Norway ++# Sweden + + # From Markus Kuhn (1998-09-29): + # The German time zone web site by the Physikalisch-Technische +@@ -1443,6 +1433,53 @@ Link Europe/Paris Europe/Monaco + # However, Moscow did not observe daylight saving in 1945, so + # this was equivalent to UT +03, not +04. + ++# Svalbard & Jan Mayen ++ ++# From Steffen Thorsen (2001-05-01): ++# Although I could not find it explicitly, it seems that Jan Mayen and ++# Svalbard have been using the same time as Norway at least since the ++# time they were declared as parts of Norway. Svalbard was declared ++# as a part of Norway by law of 1925-07-17 no 11, section 4 and Jan ++# Mayen by law of 1930-02-27 no 2, section 2. (From ++# and ++# ). The law/regulation ++# for normal/standard time in Norway is from 1894-06-29 no 1 (came ++# into operation on 1895-01-01) and Svalbard/Jan Mayen seem to be a ++# part of this law since 1925/1930. (From ++# ) I have not been ++# able to find if Jan Mayen used a different time zone (e.g. -0100) ++# before 1930. Jan Mayen has only been "inhabited" since 1921 by ++# Norwegian meteorologists and maybe used the same time as Norway ever ++# since 1921. Svalbard (Arctic/Longyearbyen) has been inhabited since ++# before 1895, and therefore probably changed the local time somewhere ++# between 1895 and 1925 (inclusive). ++ ++# From Paul Eggert (2013-09-04): ++# ++# Actually, Jan Mayen was never occupied by Germany during World War II, ++# so it must have diverged from Oslo time during the war, as Oslo was ++# keeping Berlin time. ++# ++# says that the meteorologists ++# burned down their station in 1940 and left the island, but returned in ++# 1941 with a small Norwegian garrison and continued operations despite ++# frequent air attacks from Germans. In 1943 the Americans established a ++# radiolocating station on the island, called "Atlantic City". Possibly ++# the UT offset changed during the war, but I think it unlikely that ++# Jan Mayen used German daylight-saving rules. ++# ++# Svalbard is more complicated, as it was raided in August 1941 by an ++# Allied party that evacuated the civilian population to England (says ++# ). The Svalbard FAQ ++# says that the Germans were ++# expelled on 1942-05-14. However, small parties of Germans did return, ++# and according to Wilhelm Dege's book "War North of 80" (1954) ++# http://www.ucalgary.ca/UofC/departments/UP/1-55238/1-55238-110-2.html ++# the German armed forces at the Svalbard weather station code-named ++# Haudegen did not surrender to the Allies until September 1945. ++# ++# All these events predate our cutoff date of 1970, so use Europe/Berlin ++# for these regions. + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Germany 1946 only - Apr 14 2:00s 1:00 S +@@ -1467,11 +1504,6 @@ Zone Europe/Berlin 0:53:28 - LMT 1893 Apr + 1:00 SovietZone CE%sT 1946 + 1:00 Germany CE%sT 1980 + 1:00 EU CE%sT +-Link Europe/Berlin Arctic/Longyearbyen +-Link Europe/Berlin Europe/Copenhagen +-Link Europe/Berlin Europe/Oslo +-Link Europe/Berlin Europe/Stockholm +- + + # Georgia + # Please see the "asia" file for Asia/Tbilisi. +@@ -1590,10 +1622,9 @@ Zone Europe/Budapest 1:16:20 - LMT 1890 Nov 1 + 1:00 Hungary CE%sT 1984 + 1:00 EU CE%sT + +-# Iceland +-# See Africa/Abidjan. +- + # Italy ++# San Marino ++# Vatican City + # + # From Paul Eggert (2001-03-06): + # Sicily and Sardinia each had their own time zones from 1866 to 1893, +@@ -1712,13 +1743,6 @@ Zone Europe/Rome 0:49:56 - LMT 1866 Dec 12 + 1:00 C-Eur CE%sT 1944 Jun 4 + 1:00 Italy CE%sT 1980 + 1:00 EU CE%sT +-Link Europe/Rome Europe/Vatican +-Link Europe/Rome Europe/San_Marino +- +- +-# Kosovo +-# See Europe/Belgrade. +- + + # Latvia + +@@ -1802,10 +1826,6 @@ Zone Europe/Riga 1:36:34 - LMT 1880 + 2:00 - EET 2001 Jan 2 + 2:00 EU EE%sT + +-# Liechtenstein +-# See Europe/Zurich. +- +- + # Lithuania + + # From Paul Eggert (2016-03-18): +@@ -1858,12 +1878,6 @@ Zone Europe/Vilnius 1:41:16 - LMT 1880 + 2:00 - EET 2003 Jan 1 + 2:00 EU EE%sT + +-# Luxembourg +-# See Europe/Brussels. +- +-# North Macedonia +-# See Europe/Belgrade. +- + # Malta + # + # From Paul Eggert (2016-10-21): +@@ -1959,67 +1973,6 @@ Zone Europe/Chisinau 1:55:20 - LMT 1880 + # See Romania commentary for the guessed 1997 transition to EU rules. + 2:00 Moldova EE%sT + +-# Monaco +-# See Europe/Paris. +- +-# Montenegro +-# See Europe/Belgrade. +- +-# Netherlands +-# See Europe/Brussels. +- +-# Norway +-# See Europe/Berlin. +- +-# Svalbard & Jan Mayen +- +-# From Steffen Thorsen (2001-05-01): +-# Although I could not find it explicitly, it seems that Jan Mayen and +-# Svalbard have been using the same time as Norway at least since the +-# time they were declared as parts of Norway. Svalbard was declared +-# as a part of Norway by law of 1925-07-17 no 11, section 4 and Jan +-# Mayen by law of 1930-02-27 no 2, section 2. (From +-# and +-# ). The law/regulation +-# for normal/standard time in Norway is from 1894-06-29 no 1 (came +-# into operation on 1895-01-01) and Svalbard/Jan Mayen seem to be a +-# part of this law since 1925/1930. (From +-# ) I have not been +-# able to find if Jan Mayen used a different time zone (e.g. -0100) +-# before 1930. Jan Mayen has only been "inhabited" since 1921 by +-# Norwegian meteorologists and maybe used the same time as Norway ever +-# since 1921. Svalbard (Arctic/Longyearbyen) has been inhabited since +-# before 1895, and therefore probably changed the local time somewhere +-# between 1895 and 1925 (inclusive). +- +-# From Paul Eggert (2013-09-04): +-# +-# Actually, Jan Mayen was never occupied by Germany during World War II, +-# so it must have diverged from Oslo time during the war, as Oslo was +-# keeping Berlin time. +-# +-# says that the meteorologists +-# burned down their station in 1940 and left the island, but returned in +-# 1941 with a small Norwegian garrison and continued operations despite +-# frequent air attacks from Germans. In 1943 the Americans established a +-# radiolocating station on the island, called "Atlantic City". Possibly +-# the UT offset changed during the war, but I think it unlikely that +-# Jan Mayen used German daylight-saving rules. +-# +-# Svalbard is more complicated, as it was raided in August 1941 by an +-# Allied party that evacuated the civilian population to England (says +-# ). The Svalbard FAQ +-# says that the Germans were +-# expelled on 1942-05-14. However, small parties of Germans did return, +-# and according to Wilhelm Dege's book "War North of 80" (1954) +-# http://www.ucalgary.ca/UofC/departments/UP/1-55238/1-55238-110-2.html +-# the German armed forces at the Svalbard weather station code-named +-# Haudegen did not surrender to the Allies until September 1945. +-# +-# All these events predate our cutoff date of 1970, so use Europe/Berlin +-# for these regions. +- +- + # Poland + + # The 1919 dates and times can be found in Tygodnik Urzędowy nr 1 (1919-03-20), +@@ -3301,11 +3254,13 @@ Zone Asia/Anadyr 11:49:56 - LMT 1924 May 2 + 11:00 Russia +11/+12 2011 Mar 27 2:00s + 12:00 - +12 + +- +-# San Marino +-# See Europe/Rome. +- ++# Bosnia & Herzegovina ++# Croatia ++# Kosovo ++# Montenegro ++# North Macedonia + # Serbia ++# Slovenia + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Europe/Belgrade 1:22:00 - LMT 1884 + 1:00 - CET 1941 Apr 18 23:00 +@@ -3317,17 +3272,6 @@ Zone Europe/Belgrade 1:22:00 - LMT 1884 + # Shanks & Pottenger don't give as much detail, so go with Koželj. + 1:00 - CET 1982 Nov 27 + 1:00 EU CE%sT +-Link Europe/Belgrade Europe/Ljubljana # Slovenia +-Link Europe/Belgrade Europe/Podgorica # Montenegro +-Link Europe/Belgrade Europe/Sarajevo # Bosnia and Herzegovina +-Link Europe/Belgrade Europe/Skopje # North Macedonia +-Link Europe/Belgrade Europe/Zagreb # Croatia +- +-# Slovakia +-# See Europe/Prague. +- +-# Slovenia +-# See Europe/Belgrade. + + # Spain + # +@@ -3434,10 +3378,11 @@ Zone Atlantic/Canary -1:01:36 - LMT 1922 Mar # Las Palmas de Gran C. + # IATA SSIM (1996-09) says the Canaries switch at 2:00u, not 1:00u. + # Ignore this for now, as the Canaries are part of the EU. + +-# Sweden +-# See Europe/Berlin. + ++# Germany (Busingen enclave) ++# Liechtenstein + # Switzerland ++# + # From Howse: + # By the end of the 18th century clocks and watches became commonplace + # and their performance improved enormously. Communities began to keep +@@ -3550,9 +3495,6 @@ Zone Europe/Zurich 0:34:08 - LMT 1853 Jul 16 # See above comment. + 0:29:46 - BMT 1894 Jun # Bern Mean Time + 1:00 Swiss CE%sT 1981 + 1:00 EU CE%sT +-Link Europe/Zurich Europe/Busingen +-Link Europe/Zurich Europe/Vaduz +- + + # Turkey + +@@ -3757,7 +3699,6 @@ Zone Europe/Istanbul 1:55:52 - LMT 1880 + 2:00 1:00 EEST 2015 Nov 8 1:00u + 2:00 EU EE%sT 2016 Sep 7 + 3:00 - +03 +-Link Europe/Istanbul Asia/Istanbul # Istanbul is in both continents. + + # Ukraine + # +@@ -3860,9 +3801,6 @@ Zone Europe/Kyiv 2:02:04 - LMT 1880 + 2:00 C-Eur EE%sT 1996 May 13 + 2:00 EU EE%sT + +-# Vatican City +-# See Europe/Rome. +- + ############################################################################### + + # One source shows that Bulgaria, Cyprus, Finland, and Greece observe DST from +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/northamerica b/jdk/test/sun/util/calendar/zi/tzdata/northamerica +index ce4ee74..465e8c2 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/northamerica ++++ b/jdk/test/sun/util/calendar/zi/tzdata/northamerica +@@ -852,7 +852,6 @@ Zone America/Phoenix -7:28:18 - LMT 1883 Nov 18 19:00u + -7:00 - MST 1967 + -7:00 US M%sT 1968 Mar 21 + -7:00 - MST +-Link America/Phoenix America/Creston + + # From Arthur David Olson (1988-02-13): + # A writer from the Inter Tribal Council of Arizona, Inc., +@@ -1626,23 +1625,6 @@ Zone America/Moncton -4:19:08 - LMT 1883 Dec 9 + + # Ontario + +-# From Paul Eggert (2006-07-09): +-# Shanks & Pottenger write that since 1970 most of Ontario has been like +-# Toronto. +-# Thunder Bay skipped DST in 1973. +-# Many smaller locales did not observe peacetime DST until 1974; +-# Nipigon (EST) and Rainy River (CST) are the largest that we know of. +-# Far west Ontario is like Winnipeg; far east Quebec is like Halifax. +- +-# From Jeffery Nichols (2020-02-06): +-# According to the [Shanks] atlas, those western Ontario zones are huge, +-# covering most of Ontario northwest of Sault Ste Marie and Timmins. +-# The zones seem to include towns bigger than the ones they're named after, +-# like Dryden in America/Rainy_River and Wawa (and maybe Attawapiskat) in +-# America/Nipigon. I assume it's too much trouble to change the name of the +-# zone (like when you found out that America/Glace_Bay includes Sydney, Nova +-# Scotia).... +- + # From Mark Brader (2003-07-26): + # [According to the Toronto Star] Orillia, Ontario, adopted DST + # effective Saturday, 1912-06-22, 22:00; the article mentions that +@@ -1663,17 +1645,6 @@ Zone America/Moncton -4:19:08 - LMT 1883 Dec 9 + + # From Mark Brader (2010-03-06): + # +-# Currently the database has: +-# +-# # Ontario +-# +-# # From Paul Eggert (2006-07-09): +-# # Shanks & Pottenger write that since 1970 most of Ontario has been like +-# # Toronto. +-# # Thunder Bay skipped DST in 1973. +-# # Many smaller locales did not observe peacetime DST until 1974; +-# # Nipigon (EST) and Rainy River (CST) are the largest that we know of. +-# + # In the (Toronto) Globe and Mail for Saturday, 1955-09-24, in the bottom + # right corner of page 1, it says that Toronto will return to standard + # time at 2 am Sunday morning (which agrees with the database), and that: +@@ -1681,10 +1652,8 @@ Zone America/Moncton -4:19:08 - LMT 1883 Dec 9 + # The one-hour setback will go into effect throughout most of Ontario, + # except in areas like Windsor which remains on standard time all year. + # +-# Windsor is, of course, a lot larger than Nipigon. +-# +-# I only came across this incidentally. I don't know if Windsor began +-# observing DST when Detroit did, or in 1974, or on some other date. ++# ... I don't know if Windsor began observing DST when Detroit did, ++# or in 1974, or on some other date. + # + # By the way, the article continues by noting that: + # +@@ -1766,23 +1735,7 @@ Rule Toronto 1951 1956 - Sep lastSun 2:00 0 S + # Toronto Star, which said that DST was ending 1971-10-31 as usual. + Rule Toronto 1957 1973 - Oct lastSun 2:00 0 S + +-# From Paul Eggert (2003-07-27): +-# Willett (1914-03) writes (p. 17) "In the Cities of Fort William, and +-# Port Arthur, Ontario, the principle of the Bill has been in +-# operation for the past three years, and in the City of Moose Jaw, +-# Saskatchewan, for one year." +- +-# From David Bryan via Tory Tronrud, Director/Curator, +-# Thunder Bay Museum (2003-11-12): +-# There is some suggestion, however, that, by-law or not, daylight +-# savings time was being practiced in Fort William and Port Arthur +-# before 1909.... [I]n 1910, the line between the Eastern and Central +-# Time Zones was permanently moved about two hundred miles west to +-# include the Thunder Bay area.... When Canada adopted daylight +-# savings time in 1916, Fort William and Port Arthur, having done so +-# already, did not change their clocks.... During the Second World +-# War,... [t]he cities agreed to implement DST during the summer +-# months for the remainder of the war years. ++# The Bahamas match Toronto since 1970. + + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone America/Toronto -5:17:32 - LMT 1895 +@@ -1791,22 +1744,6 @@ Zone America/Toronto -5:17:32 - LMT 1895 + -5:00 Canada E%sT 1946 + -5:00 Toronto E%sT 1974 + -5:00 Canada E%sT +-Link America/Toronto America/Nassau +-Zone America/Thunder_Bay -5:57:00 - LMT 1895 +- -6:00 - CST 1910 +- -5:00 - EST 1942 +- -5:00 Canada E%sT 1970 +- -5:00 Toronto E%sT 1973 +- -5:00 - EST 1974 +- -5:00 Canada E%sT +-Zone America/Nipigon -5:53:04 - LMT 1895 +- -5:00 Canada E%sT 1940 Sep 29 +- -5:00 1:00 EDT 1942 Feb 9 2:00s +- -5:00 Canada E%sT +-Zone America/Rainy_River -6:18:16 - LMT 1895 +- -6:00 Canada C%sT 1940 Sep 29 +- -6:00 1:00 CDT 1942 Feb 9 2:00s +- -6:00 Canada C%sT + # For Atikokan see America/Panama. + + +@@ -2639,6 +2576,12 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 + # 5- The islands, reefs and keys shall take their timezone from the + # longitude they are located at. + ++# From Paul Eggert (2022-10-28): ++# The new Mexican law was published today: ++# https://www.dof.gob.mx/nota_detalle.php?codigo=5670045&fecha=28/10/2022 ++# This abolishes DST except where US DST rules are observed, ++# and in addition changes all of Chihuahua to -06 with no DST. ++ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Mexico 1931 only - May 1 23:00 1:00 D + Rule Mexico 1931 only - Oct 1 0:00 0 S +@@ -2654,8 +2597,8 @@ Rule Mexico 1996 2000 - Apr Sun>=1 2:00 1:00 D + Rule Mexico 1996 2000 - Oct lastSun 2:00 0 S + Rule Mexico 2001 only - May Sun>=1 2:00 1:00 D + Rule Mexico 2001 only - Sep lastSun 2:00 0 S +-Rule Mexico 2002 max - Apr Sun>=1 2:00 1:00 D +-Rule Mexico 2002 max - Oct lastSun 2:00 0 S ++Rule Mexico 2002 2022 - Apr Sun>=1 2:00 1:00 D ++Rule Mexico 2002 2022 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] + # Quintana Roo; represented by Cancún + Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 6:00u +@@ -2708,7 +2651,8 @@ Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u + -6:00 Mexico C%sT 1998 + -6:00 - CST 1998 Apr Sun>=1 3:00 + -7:00 Mexico M%sT 2010 +- -7:00 US M%sT ++ -7:00 US M%sT 2022 Oct 30 2:00 ++ -6:00 - CST + # Chihuahua (away from US border) + Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 +@@ -2717,7 +2661,8 @@ Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u + -6:00 - CST 1996 + -6:00 Mexico C%sT 1998 + -6:00 - CST 1998 Apr Sun>=1 3:00 +- -7:00 Mexico M%sT ++ -7:00 Mexico M%sT 2022 Oct 30 2:00 ++ -6:00 - CST + # Sonora + Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 +@@ -2815,20 +2760,16 @@ Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 7:00u + # http://dof.gob.mx/nota_detalle.php?codigo=5127480&fecha=06/01/2010 + # It has been moved to the 'backward' file. + # ++# From Paul Eggert (2022-10-28): ++# Today's new law states that the entire state of Baja California ++# follows US DST rules, which agrees with simplifications noted above. ++# + # + # Revillagigedo Is + # no information + + ############################################################################### + +-# Anguilla +-# Antigua and Barbuda +-# See America/Puerto_Rico. +- +-# The Bahamas +-# See America/Toronto. +- +- + # Barbados + + # For 1899 Milne gives -3:58:29.2. +@@ -3041,12 +2982,6 @@ Zone Atlantic/Bermuda -4:19:18 - LMT 1890 # Hamilton + -4:00 Canada A%sT 1976 + -4:00 US A%sT + +-# Caribbean Netherlands +-# See America/Puerto_Rico. +- +-# Cayman Is +-# See America/Panama. +- + # Costa Rica + + # Milne gives -5:36:13.3 as San José mean time. +@@ -3272,9 +3207,6 @@ Zone America/Havana -5:29:28 - LMT 1890 + -5:29:36 - HMT 1925 Jul 19 12:00 # Havana MT + -5:00 Cuba C%sT + +-# Dominica +-# See America/Puerto_Rico. +- + # Dominican Republic + + # From Steffen Thorsen (2000-10-30): +@@ -3321,12 +3253,6 @@ Rule Salv 1987 1988 - Sep lastSun 0:00 0 S + Zone America/El_Salvador -5:56:48 - LMT 1921 # San Salvador + -6:00 Salv C%sT + +-# Grenada +-# Guadeloupe +-# St Barthélemy +-# St Martin (French part) +-# See America/Puerto_Rico. +- + # Guatemala + # + # From Gwillim Law (2006-04-22), after a heads-up from Oscar van Vlijmen: +@@ -3512,9 +3438,6 @@ Zone America/Martinique -4:04:20 - LMT 1890 # Fort-de-France + -4:00 1:00 ADT 1980 Sep 28 + -4:00 - AST + +-# Montserrat +-# See America/Puerto_Rico. +- + # Nicaragua + # + # This uses Shanks & Pottenger for times before 2005. +@@ -3580,44 +3503,39 @@ Zone America/Managua -5:45:08 - LMT 1890 + -5:00 - EST 1997 + -6:00 Nic C%sT + ++# Cayman Is + # Panama ++# ++# Atikokan and Coral Harbour, Canada, match Panama since 1970. + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone America/Panama -5:18:08 - LMT 1890 + -5:19:36 - CMT 1908 Apr 22 # Colón Mean Time + -5:00 - EST +-Link America/Panama America/Atikokan +-Link America/Panama America/Cayman + ++# Anguilla ++# Antigua & Barbuda ++# Aruba ++# Caribbean Netherlands ++# Curaçao ++# Dominica ++# Grenada ++# Guadeloupe ++# Montserrat + # Puerto Rico ++# St Barthélemy ++# St Kitts-Nevis ++# Sint Maarten / St Martin ++# St Lucia ++# St Vincent & the Grenadines ++# Trinidad & Tobago ++# Virgin Is (UK & US) ++# + # There are too many San Juans elsewhere, so we'll use 'Puerto_Rico'. + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone America/Puerto_Rico -4:24:25 - LMT 1899 Mar 28 12:00 # San Juan + -4:00 - AST 1942 May 3 + -4:00 US A%sT 1946 + -4:00 - AST +-Link America/Puerto_Rico America/Anguilla +-Link America/Puerto_Rico America/Antigua +-Link America/Puerto_Rico America/Aruba +-Link America/Puerto_Rico America/Curacao +-Link America/Puerto_Rico America/Blanc-Sablon # Quebec (Lower North Shore) +-Link America/Puerto_Rico America/Dominica +-Link America/Puerto_Rico America/Grenada +-Link America/Puerto_Rico America/Guadeloupe +-Link America/Puerto_Rico America/Kralendijk # Caribbean Netherlands +-Link America/Puerto_Rico America/Lower_Princes # Sint Maarten +-Link America/Puerto_Rico America/Marigot # St Martin (French part) +-Link America/Puerto_Rico America/Montserrat +-Link America/Puerto_Rico America/Port_of_Spain # Trinidad & Tobago +-Link America/Puerto_Rico America/St_Barthelemy # St Barthélemy +-Link America/Puerto_Rico America/St_Kitts # St Kitts & Nevis +-Link America/Puerto_Rico America/St_Lucia +-Link America/Puerto_Rico America/St_Thomas # Virgin Islands (US) +-Link America/Puerto_Rico America/St_Vincent +-Link America/Puerto_Rico America/Tortola # Virgin Islands (UK) +- +-# St Kitts-Nevis +-# St Lucia +-# See America/Puerto_Rico. + + # St Pierre and Miquelon + # There are too many St Pierres elsewhere, so we'll use 'Miquelon'. +@@ -3627,12 +3545,6 @@ Zone America/Miquelon -3:44:40 - LMT 1911 May 15 # St Pierre + -3:00 - -03 1987 + -3:00 Canada -03/-02 + +-# St Vincent and the Grenadines +-# See America/Puerto_Rico. +- +-# Sint Maarten +-# See America/Puerto_Rico. +- + # Turks and Caicos + # + # From Chris Dunn in +@@ -3702,11 +3614,6 @@ Zone America/Grand_Turk -4:44:32 - LMT 1890 + -4:00 - AST 2018 Mar 11 3:00 + -5:00 US E%sT + +-# British Virgin Is +-# US Virgin Is +-# See America/Puerto_Rico. +- +- + # Local Variables: + # coding: utf-8 + # End: +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/southamerica b/jdk/test/sun/util/calendar/zi/tzdata/southamerica +index 3c0e0e2..982ad09 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/southamerica ++++ b/jdk/test/sun/util/calendar/zi/tzdata/southamerica +@@ -608,9 +608,6 @@ Zone America/Argentina/Ushuaia -4:33:12 - LMT 1894 Oct 31 + -3:00 Arg -03/-02 2008 Oct 18 + -3:00 - -03 + +-# Aruba +-# See America/Puerto_Rico. +- + # Bolivia + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone America/La_Paz -4:32:36 - LMT 1890 +@@ -1455,15 +1452,6 @@ Zone America/Bogota -4:56:16 - LMT 1884 Mar 13 + # Malpelo, Providencia, San Andres + # no information; probably like America/Bogota + +-# Curaçao +-# See America/Puerto_Rico. +-# +-# From Arthur David Olson (2011-06-15): +-# use links for places with new iso3166 codes. +-# The name "Lower Prince's Quarter" is both longer than fourteen characters +-# and contains an apostrophe; use "Lower_Princes".... +-# From Paul Eggert (2021-09-29): +-# These backward-compatibility links now are in the 'northamerica' file. + + # Ecuador + # +@@ -1779,9 +1767,6 @@ Zone America/Paramaribo -3:40:40 - LMT 1911 + -3:30 - -0330 1984 Oct + -3:00 - -03 + +-# Trinidad and Tobago +-# See America/Puerto_Rico. +- + # Uruguay + # From Paul Eggert (1993-11-18): + # Uruguay wins the prize for the strangest peacetime manipulation of the rules. +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/zone.tab b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab +index ee02519..535d1c9 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/zone.tab ++++ b/jdk/test/sun/util/calendar/zi/tzdata/zone.tab +@@ -137,13 +137,10 @@ CA +4606-06447 America/Moncton Atlantic - New Brunswick + CA +5320-06025 America/Goose_Bay Atlantic - Labrador (most areas) + CA +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) + CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) +-CA +4901-08816 America/Nipigon Eastern - ON, QC (no DST 1967-73) +-CA +4823-08915 America/Thunder_Bay Eastern - ON (Thunder Bay) + CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) + CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) + CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) + CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +-CA +4843-09434 America/Rainy_River Central - ON (Rainy R, Ft Frances) + CA +744144-0944945 America/Resolute Central - NU (Resolute) + CA +624900-0920459 America/Rankin_Inlet Central - NU (central) + CA +5024-10439 America/Regina CST - SK (most areas) +-- +1.8.3.1 diff --git a/8296241-tz-Update-Timezone-Data-to-2022e.patch b/8296241-tz-Update-Timezone-Data-to-2022e.patch new file mode 100644 index 0000000..699894c --- /dev/null +++ b/8296241-tz-Update-Timezone-Data-to-2022e.patch @@ -0,0 +1,826 @@ +From d31b6120315ecc095ddffa7a5fb92c53bb70bc3b Mon Sep 17 00:00:00 2001 +From: eapen +Date: Wed, 30 Nov 2022 14:57:07 +0000 +Subject: [PATCH 08/33] I68TO2: 8296241: (tz) Update Timezone Data to 2022e +--- + jdk/make/data/tzdata/VERSION | 2 +- + jdk/make/data/tzdata/asia | 36 +++++++--- + jdk/make/data/tzdata/europe | 2 +- + jdk/make/data/tzdata/northamerica | 84 ++++++++++------------ + jdk/test/java/util/TimeZone/TimeZoneData/VERSION | 2 +- + .../util/TimeZone/TimeZoneData/displaynames.txt | 2 - + jdk/test/sun/util/calendar/zi/tzdata/VERSION | 2 +- + jdk/test/sun/util/calendar/zi/tzdata/asia | 36 +++++++--- + jdk/test/sun/util/calendar/zi/tzdata/europe | 2 +- + jdk/test/sun/util/calendar/zi/tzdata/northamerica | 84 ++++++++++------------ + 10 files changed, 135 insertions(+), 117 deletions(-) + +diff --git a/jdk/make/data/tzdata/VERSION b/jdk/make/data/tzdata/VERSION +index 889d0e6..b8cb36e 100644 +--- a/jdk/make/data/tzdata/VERSION ++++ b/jdk/make/data/tzdata/VERSION +@@ -21,4 +21,4 @@ + # or visit www.oracle.com if you need additional information or have any + # questions. + # +-tzdata2022d ++tzdata2022e +diff --git a/jdk/make/data/tzdata/asia b/jdk/make/data/tzdata/asia +index 1dc7d34..f1771e4 100644 +--- a/jdk/make/data/tzdata/asia ++++ b/jdk/make/data/tzdata/asia +@@ -2254,6 +2254,17 @@ Zone Asia/Tokyo 9:18:59 - LMT 1887 Dec 31 15:00u + # From the Arabic version, it seems to say it would be at midnight + # (assume 24:00) on the last Thursday in February, starting from 2022. + ++# From Issam Al-Zuwairi (2022-10-05): ++# The Council of Ministers in Jordan decided Wednesday 5th October 2022, ++# that daylight saving time (DST) will be throughout the year.... ++# ++# From Brian Inglis (2022-10-06): ++# https://petra.gov.jo/Include/InnerPage.jsp?ID=45567&lang=en&name=en_news ++# ++# From Paul Eggert (2022-10-05): ++# Like Syria, model this as a transition from EEST +03 (DST) to plain +03 ++# (non-DST) at the point where DST would otherwise have ended. ++ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Jordan 1973 only - Jun 6 0:00 1:00 S + Rule Jordan 1973 1975 - Oct 1 0:00 0 - +@@ -2285,11 +2296,12 @@ Rule Jordan 2005 only - Sep lastFri 0:00s 0 - + Rule Jordan 2006 2011 - Oct lastFri 0:00s 0 - + Rule Jordan 2013 only - Dec 20 0:00 0 - + Rule Jordan 2014 2021 - Mar lastThu 24:00 1:00 S +-Rule Jordan 2014 max - Oct lastFri 0:00s 0 - +-Rule Jordan 2022 max - Feb lastThu 24:00 1:00 S ++Rule Jordan 2014 2022 - Oct lastFri 0:00s 0 - ++Rule Jordan 2022 only - Feb lastThu 24:00 1:00 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Amman 2:23:44 - LMT 1931 +- 2:00 Jordan EE%sT ++ 2:00 Jordan EE%sT 2022 Oct 28 0:00s ++ 3:00 - +03 + + + # Kazakhstan +@@ -3838,19 +3850,27 @@ Rule Syria 2007 only - Nov Fri>=1 0:00 0 - + # Our brief summary: + # https://www.timeanddate.com/news/time/syria-dst-2012.html + +-# From Arthur David Olson (2012-03-27): +-# Assume last Friday in March going forward XXX. ++# From Steffen Thorsen (2022-10-05): ++# Syria is adopting year-round DST, starting this autumn.... ++# From https://www.enabbaladi.net/archives/607812 ++# "This [the decision] came after the weekly government meeting today, ++# Tuesday 4 October ..." ++# ++# From Paul Eggert (2022-10-05): ++# Like Jordan, model this as a transition from EEST +03 (DST) to plain +03 ++# (non-DST) at the point where DST would otherwise have ended. + + Rule Syria 2008 only - Apr Fri>=1 0:00 1:00 S + Rule Syria 2008 only - Nov 1 0:00 0 - + Rule Syria 2009 only - Mar lastFri 0:00 1:00 S + Rule Syria 2010 2011 - Apr Fri>=1 0:00 1:00 S +-Rule Syria 2012 max - Mar lastFri 0:00 1:00 S +-Rule Syria 2009 max - Oct lastFri 0:00 0 - ++Rule Syria 2012 2022 - Mar lastFri 0:00 1:00 S ++Rule Syria 2009 2022 - Oct lastFri 0:00 0 - + + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Damascus 2:25:12 - LMT 1920 # Dimashq +- 2:00 Syria EE%sT ++ 2:00 Syria EE%sT 2022 Oct 28 0:00 ++ 3:00 - +03 + + # Tajikistan + # From Shanks & Pottenger. +diff --git a/jdk/make/data/tzdata/europe b/jdk/make/data/tzdata/europe +index 9e0a538..930cede 100644 +--- a/jdk/make/data/tzdata/europe ++++ b/jdk/make/data/tzdata/europe +@@ -3417,7 +3417,7 @@ Zone Europe/Madrid -0:14:44 - LMT 1901 Jan 1 0:00u + 0:00 Spain WE%sT 1940 Mar 16 23:00 + 1:00 Spain CE%sT 1979 + 1:00 EU CE%sT +-Zone Africa/Ceuta -0:21:16 - LMT 1900 Dec 31 23:38:44 ++Zone Africa/Ceuta -0:21:16 - LMT 1901 Jan 1 0:00u + 0:00 - WET 1918 May 6 23:00 + 0:00 1:00 WEST 1918 Oct 7 23:00 + 0:00 - WET 1924 +diff --git a/jdk/make/data/tzdata/northamerica b/jdk/make/data/tzdata/northamerica +index 114cef1..ce4ee74 100644 +--- a/jdk/make/data/tzdata/northamerica ++++ b/jdk/make/data/tzdata/northamerica +@@ -462,7 +462,7 @@ Rule Chicago 1922 1966 - Apr lastSun 2:00 1:00 D + Rule Chicago 1922 1954 - Sep lastSun 2:00 0 S + Rule Chicago 1955 1966 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24 ++Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1920 + -6:00 Chicago C%sT 1936 Mar 1 2:00 + -5:00 - EST 1936 Nov 15 2:00 +@@ -471,7 +471,7 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24 + -6:00 Chicago C%sT 1967 + -6:00 US C%sT + # Oliver County, ND switched from mountain to central time on 1992-10-25. +-Zone America/North_Dakota/Center -6:45:12 - LMT 1883 Nov 18 12:14:48 ++Zone America/North_Dakota/Center -6:45:12 - LMT 1883 Nov 18 19:00u + -7:00 US M%sT 1992 Oct 25 2:00 + -6:00 US C%sT + # Morton County, ND, switched from mountain to central time on +@@ -481,7 +481,7 @@ Zone America/North_Dakota/Center -6:45:12 - LMT 1883 Nov 18 12:14:48 + # Jones, Mellette, and Todd Counties in South Dakota; + # but in practice these other counties were already observing central time. + # See . +-Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21 ++Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 19:00u + -7:00 US M%sT 2003 Oct 26 2:00 + -6:00 US C%sT + +@@ -498,7 +498,7 @@ Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21 + # largest city in Mercer County). Google Maps places Beulah's city hall + # at 47° 15' 51" N, 101° 46' 40" W, which yields an offset of 6h47'07". + +-Zone America/North_Dakota/Beulah -6:47:07 - LMT 1883 Nov 18 12:12:53 ++Zone America/North_Dakota/Beulah -6:47:07 - LMT 1883 Nov 18 19:00u + -7:00 US M%sT 2010 Nov 7 2:00 + -6:00 US C%sT + +@@ -530,7 +530,7 @@ Rule Denver 1921 only - May 22 2:00 0 S + Rule Denver 1965 1966 - Apr lastSun 2:00 1:00 D + Rule Denver 1965 1966 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Denver -6:59:56 - LMT 1883 Nov 18 12:00:04 ++Zone America/Denver -6:59:56 - LMT 1883 Nov 18 19:00u + -7:00 US M%sT 1920 + -7:00 Denver M%sT 1942 + -7:00 US M%sT 1946 +@@ -583,7 +583,7 @@ Rule CA 1950 1966 - Apr lastSun 1:00 1:00 D + Rule CA 1950 1961 - Sep lastSun 2:00 0 S + Rule CA 1962 1966 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Los_Angeles -7:52:58 - LMT 1883 Nov 18 12:07:02 ++Zone America/Los_Angeles -7:52:58 - LMT 1883 Nov 18 20:00u + -8:00 US P%sT 1946 + -8:00 CA P%sT 1967 + -8:00 US P%sT +@@ -845,7 +845,7 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00 + # Go with the Arizona State Library instead. + + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Phoenix -7:28:18 - LMT 1883 Nov 18 11:31:42 ++Zone America/Phoenix -7:28:18 - LMT 1883 Nov 18 19:00u + -7:00 US M%sT 1944 Jan 1 0:01 + -7:00 - MST 1944 Apr 1 0:01 + -7:00 US M%sT 1944 Oct 1 0:01 +@@ -873,7 +873,7 @@ Link America/Phoenix America/Creston + # switched four weeks late in 1974. + # + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Boise -7:44:49 - LMT 1883 Nov 18 12:15:11 ++Zone America/Boise -7:44:49 - LMT 1883 Nov 18 20:00u + -8:00 US P%sT 1923 May 13 2:00 + -7:00 US M%sT 1974 + -7:00 - MST 1974 Feb 3 2:00 +@@ -945,7 +945,7 @@ Rule Indianapolis 1941 only - Jun 22 2:00 1:00 D + Rule Indianapolis 1941 1954 - Sep lastSun 2:00 0 S + Rule Indianapolis 1946 1954 - Apr lastSun 2:00 1:00 D + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Indianapolis -5:44:38 - LMT 1883 Nov 18 12:15:22 ++Zone America/Indiana/Indianapolis -5:44:38 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1920 + -6:00 Indianapolis C%sT 1942 + -6:00 US C%sT 1946 +@@ -965,7 +965,7 @@ Rule Marengo 1951 only - Sep lastSun 2:00 0 S + Rule Marengo 1954 1960 - Apr lastSun 2:00 1:00 D + Rule Marengo 1954 1960 - Sep lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Marengo -5:45:23 - LMT 1883 Nov 18 12:14:37 ++Zone America/Indiana/Marengo -5:45:23 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1951 + -6:00 Marengo C%sT 1961 Apr 30 2:00 + -5:00 - EST 1969 +@@ -989,7 +989,7 @@ Rule Vincennes 1960 only - Oct lastSun 2:00 0 S + Rule Vincennes 1961 only - Sep lastSun 2:00 0 S + Rule Vincennes 1962 1963 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Vincennes -5:50:07 - LMT 1883 Nov 18 12:09:53 ++Zone America/Indiana/Vincennes -5:50:07 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1946 + -6:00 Vincennes C%sT 1964 Apr 26 2:00 + -5:00 - EST 1969 +@@ -1009,7 +1009,7 @@ Rule Perry 1955 1960 - Sep lastSun 2:00 0 S + Rule Perry 1956 1963 - Apr lastSun 2:00 1:00 D + Rule Perry 1961 1963 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Tell_City -5:47:03 - LMT 1883 Nov 18 12:12:57 ++Zone America/Indiana/Tell_City -5:47:03 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1946 + -6:00 Perry C%sT 1964 Apr 26 2:00 + -5:00 - EST 1967 Oct 29 2:00 +@@ -1026,7 +1026,7 @@ Rule Pike 1955 1960 - Sep lastSun 2:00 0 S + Rule Pike 1956 1964 - Apr lastSun 2:00 1:00 D + Rule Pike 1961 1964 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Petersburg -5:49:07 - LMT 1883 Nov 18 12:10:53 ++Zone America/Indiana/Petersburg -5:49:07 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1955 + -6:00 Pike C%sT 1965 Apr 25 2:00 + -5:00 - EST 1966 Oct 30 2:00 +@@ -1048,7 +1048,7 @@ Rule Starke 1955 1956 - Oct lastSun 2:00 0 S + Rule Starke 1957 1958 - Sep lastSun 2:00 0 S + Rule Starke 1959 1961 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Knox -5:46:30 - LMT 1883 Nov 18 12:13:30 ++Zone America/Indiana/Knox -5:46:30 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1947 + -6:00 Starke C%sT 1962 Apr 29 2:00 + -5:00 - EST 1963 Oct 27 2:00 +@@ -1064,7 +1064,7 @@ Rule Pulaski 1946 1954 - Sep lastSun 2:00 0 S + Rule Pulaski 1955 1956 - Oct lastSun 2:00 0 S + Rule Pulaski 1957 1960 - Sep lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Winamac -5:46:25 - LMT 1883 Nov 18 12:13:35 ++Zone America/Indiana/Winamac -5:46:25 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1946 + -6:00 Pulaski C%sT 1961 Apr 30 2:00 + -5:00 - EST 1969 +@@ -1075,7 +1075,7 @@ Zone America/Indiana/Winamac -5:46:25 - LMT 1883 Nov 18 12:13:35 + # + # Switzerland County, Indiana, did not observe DST from 1973 through 2005. + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Vevay -5:40:16 - LMT 1883 Nov 18 12:19:44 ++Zone America/Indiana/Vevay -5:40:16 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1954 Apr 25 2:00 + -5:00 - EST 1969 + -5:00 US E%sT 1973 +@@ -1111,7 +1111,7 @@ Rule Louisville 1950 1961 - Apr lastSun 2:00 1:00 D + Rule Louisville 1950 1955 - Sep lastSun 2:00 0 S + Rule Louisville 1956 1961 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Kentucky/Louisville -5:43:02 - LMT 1883 Nov 18 12:16:58 ++Zone America/Kentucky/Louisville -5:43:02 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1921 + -6:00 Louisville C%sT 1942 + -6:00 US C%sT 1946 +@@ -1145,7 +1145,7 @@ Zone America/Kentucky/Louisville -5:43:02 - LMT 1883 Nov 18 12:16:58 + # Federal Register 65, 160 (2000-08-17), pp 50154-50158. + # https://www.gpo.gov/fdsys/pkg/FR-2000-08-17/html/00-20854.htm + # +-Zone America/Kentucky/Monticello -5:39:24 - LMT 1883 Nov 18 12:20:36 ++Zone America/Kentucky/Monticello -5:39:24 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1946 + -6:00 - CST 1968 + -6:00 US C%sT 2000 Oct 29 2:00 +@@ -2640,6 +2640,8 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 + # longitude they are located at. + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S ++Rule Mexico 1931 only - May 1 23:00 1:00 D ++Rule Mexico 1931 only - Oct 1 0:00 0 S + Rule Mexico 1939 only - Feb 5 0:00 1:00 D + Rule Mexico 1939 only - Jun 25 0:00 0 S + Rule Mexico 1940 only - Dec 9 0:00 1:00 D +@@ -2656,13 +2658,13 @@ Rule Mexico 2002 max - Apr Sun>=1 2:00 1:00 D + Rule Mexico 2002 max - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] + # Quintana Roo; represented by Cancún +-Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 0:12:56 ++Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 6:00u + -6:00 - CST 1981 Dec 23 + -5:00 Mexico E%sT 1998 Aug 2 2:00 + -6:00 Mexico C%sT 2015 Feb 1 2:00 + -5:00 - EST + # Campeche, Yucatán; represented by Mérida +-Zone America/Merida -5:58:28 - LMT 1922 Jan 1 0:01:32 ++Zone America/Merida -5:58:28 - LMT 1922 Jan 1 6:00u + -6:00 - CST 1981 Dec 23 + -5:00 - EST 1982 Dec 2 + -6:00 Mexico C%sT +@@ -2676,23 +2678,21 @@ Zone America/Merida -5:58:28 - LMT 1922 Jan 1 0:01:32 + # See: Inicia mañana Horario de Verano en zona fronteriza, El Universal, + # 2016-03-12 + # http://www.eluniversal.com.mx/articulo/estados/2016/03/12/inicia-manana-horario-de-verano-en-zona-fronteriza +-Zone America/Matamoros -6:40:00 - LMT 1921 Dec 31 23:20:00 ++Zone America/Matamoros -6:30:00 - LMT 1922 Jan 1 6:00u + -6:00 - CST 1988 + -6:00 US C%sT 1989 + -6:00 Mexico C%sT 2010 + -6:00 US C%sT + # Durango; Coahuila, Nuevo León, Tamaulipas (away from US border) +-Zone America/Monterrey -6:41:16 - LMT 1921 Dec 31 23:18:44 ++Zone America/Monterrey -6:41:16 - LMT 1922 Jan 1 6:00u + -6:00 - CST 1988 + -6:00 US C%sT 1989 + -6:00 Mexico C%sT + # Central Mexico +-Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 0:23:24 ++Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 Mexico C%sT 2001 Sep 30 2:00 + -6:00 - CST 2002 Feb 20 + -6:00 Mexico C%sT +@@ -2700,35 +2700,29 @@ Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 0:23:24 + # This includes the municipalities of Janos, Ascensión, Juárez, Guadalupe, + # Práxedis G Guerrero, Coyame del Sotol, Ojinaga, and Manuel Benavides. + # (See the 2016-03-12 El Universal source mentioned above.) +-Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 0:02:20 ++Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1996 + -6:00 Mexico C%sT 1998 + -6:00 - CST 1998 Apr Sun>=1 3:00 + -7:00 Mexico M%sT 2010 + -7:00 US M%sT + # Chihuahua (away from US border) +-Zone America/Chihuahua -7:04:20 - LMT 1921 Dec 31 23:55:40 ++Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1996 + -6:00 Mexico C%sT 1998 + -6:00 - CST 1998 Apr Sun>=1 3:00 + -7:00 Mexico M%sT + # Sonora +-Zone America/Hermosillo -7:23:52 - LMT 1921 Dec 31 23:36:08 ++Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1942 Apr 24 + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1970 +@@ -2763,24 +2757,20 @@ Zone America/Hermosillo -7:23:52 - LMT 1921 Dec 31 23:36:08 + # Use "Bahia_Banderas" to keep the name to fourteen characters. + + # Mazatlán +-Zone America/Mazatlan -7:05:40 - LMT 1921 Dec 31 23:54:20 ++Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1942 Apr 24 + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1970 + -7:00 Mexico M%sT + + # Bahía de Banderas +-Zone America/Bahia_Banderas -7:01:00 - LMT 1921 Dec 31 23:59:00 ++Zone America/Bahia_Banderas -7:01:00 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1942 Apr 24 + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1970 +@@ -2788,7 +2778,7 @@ Zone America/Bahia_Banderas -7:01:00 - LMT 1921 Dec 31 23:59:00 + -6:00 Mexico C%sT + + # Baja California +-Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 0:11:56 ++Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1924 + -8:00 - PST 1927 Jun 10 23:00 + -7:00 - MST 1930 Nov 15 +diff --git a/jdk/test/java/util/TimeZone/TimeZoneData/VERSION b/jdk/test/java/util/TimeZone/TimeZoneData/VERSION +index 7147016..0cad939 100644 +--- a/jdk/test/java/util/TimeZone/TimeZoneData/VERSION ++++ b/jdk/test/java/util/TimeZone/TimeZoneData/VERSION +@@ -1 +1 @@ +-tzdata2022d ++tzdata2022e +diff --git a/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt b/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt +index b382395..2f2786f 100644 +--- a/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt ++++ b/jdk/test/java/util/TimeZone/TimeZoneData/displaynames.txt +@@ -97,9 +97,7 @@ America/Winnipeg CST CDT + America/Yakutat AKST AKDT + America/Yellowknife MST MDT + Antarctica/Macquarie AEST AEDT +-Asia/Amman EET EEST + Asia/Beirut EET EEST +-Asia/Damascus EET EEST + Asia/Famagusta EET EEST + Asia/Gaza EET EEST + Asia/Hebron EET EEST +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/VERSION b/jdk/test/sun/util/calendar/zi/tzdata/VERSION +index 889d0e6..b8cb36e 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/VERSION ++++ b/jdk/test/sun/util/calendar/zi/tzdata/VERSION +@@ -21,4 +21,4 @@ + # or visit www.oracle.com if you need additional information or have any + # questions. + # +-tzdata2022d ++tzdata2022e +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/asia b/jdk/test/sun/util/calendar/zi/tzdata/asia +index 1dc7d34..f1771e4 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/asia ++++ b/jdk/test/sun/util/calendar/zi/tzdata/asia +@@ -2254,6 +2254,17 @@ Zone Asia/Tokyo 9:18:59 - LMT 1887 Dec 31 15:00u + # From the Arabic version, it seems to say it would be at midnight + # (assume 24:00) on the last Thursday in February, starting from 2022. + ++# From Issam Al-Zuwairi (2022-10-05): ++# The Council of Ministers in Jordan decided Wednesday 5th October 2022, ++# that daylight saving time (DST) will be throughout the year.... ++# ++# From Brian Inglis (2022-10-06): ++# https://petra.gov.jo/Include/InnerPage.jsp?ID=45567&lang=en&name=en_news ++# ++# From Paul Eggert (2022-10-05): ++# Like Syria, model this as a transition from EEST +03 (DST) to plain +03 ++# (non-DST) at the point where DST would otherwise have ended. ++ + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S + Rule Jordan 1973 only - Jun 6 0:00 1:00 S + Rule Jordan 1973 1975 - Oct 1 0:00 0 - +@@ -2285,11 +2296,12 @@ Rule Jordan 2005 only - Sep lastFri 0:00s 0 - + Rule Jordan 2006 2011 - Oct lastFri 0:00s 0 - + Rule Jordan 2013 only - Dec 20 0:00 0 - + Rule Jordan 2014 2021 - Mar lastThu 24:00 1:00 S +-Rule Jordan 2014 max - Oct lastFri 0:00s 0 - +-Rule Jordan 2022 max - Feb lastThu 24:00 1:00 S ++Rule Jordan 2014 2022 - Oct lastFri 0:00s 0 - ++Rule Jordan 2022 only - Feb lastThu 24:00 1:00 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Amman 2:23:44 - LMT 1931 +- 2:00 Jordan EE%sT ++ 2:00 Jordan EE%sT 2022 Oct 28 0:00s ++ 3:00 - +03 + + + # Kazakhstan +@@ -3838,19 +3850,27 @@ Rule Syria 2007 only - Nov Fri>=1 0:00 0 - + # Our brief summary: + # https://www.timeanddate.com/news/time/syria-dst-2012.html + +-# From Arthur David Olson (2012-03-27): +-# Assume last Friday in March going forward XXX. ++# From Steffen Thorsen (2022-10-05): ++# Syria is adopting year-round DST, starting this autumn.... ++# From https://www.enabbaladi.net/archives/607812 ++# "This [the decision] came after the weekly government meeting today, ++# Tuesday 4 October ..." ++# ++# From Paul Eggert (2022-10-05): ++# Like Jordan, model this as a transition from EEST +03 (DST) to plain +03 ++# (non-DST) at the point where DST would otherwise have ended. + + Rule Syria 2008 only - Apr Fri>=1 0:00 1:00 S + Rule Syria 2008 only - Nov 1 0:00 0 - + Rule Syria 2009 only - Mar lastFri 0:00 1:00 S + Rule Syria 2010 2011 - Apr Fri>=1 0:00 1:00 S +-Rule Syria 2012 max - Mar lastFri 0:00 1:00 S +-Rule Syria 2009 max - Oct lastFri 0:00 0 - ++Rule Syria 2012 2022 - Mar lastFri 0:00 1:00 S ++Rule Syria 2009 2022 - Oct lastFri 0:00 0 - + + # Zone NAME STDOFF RULES FORMAT [UNTIL] + Zone Asia/Damascus 2:25:12 - LMT 1920 # Dimashq +- 2:00 Syria EE%sT ++ 2:00 Syria EE%sT 2022 Oct 28 0:00 ++ 3:00 - +03 + + # Tajikistan + # From Shanks & Pottenger. +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/europe b/jdk/test/sun/util/calendar/zi/tzdata/europe +index 9e0a538..930cede 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/europe ++++ b/jdk/test/sun/util/calendar/zi/tzdata/europe +@@ -3417,7 +3417,7 @@ Zone Europe/Madrid -0:14:44 - LMT 1901 Jan 1 0:00u + 0:00 Spain WE%sT 1940 Mar 16 23:00 + 1:00 Spain CE%sT 1979 + 1:00 EU CE%sT +-Zone Africa/Ceuta -0:21:16 - LMT 1900 Dec 31 23:38:44 ++Zone Africa/Ceuta -0:21:16 - LMT 1901 Jan 1 0:00u + 0:00 - WET 1918 May 6 23:00 + 0:00 1:00 WEST 1918 Oct 7 23:00 + 0:00 - WET 1924 +diff --git a/jdk/test/sun/util/calendar/zi/tzdata/northamerica b/jdk/test/sun/util/calendar/zi/tzdata/northamerica +index 114cef1..ce4ee74 100644 +--- a/jdk/test/sun/util/calendar/zi/tzdata/northamerica ++++ b/jdk/test/sun/util/calendar/zi/tzdata/northamerica +@@ -462,7 +462,7 @@ Rule Chicago 1922 1966 - Apr lastSun 2:00 1:00 D + Rule Chicago 1922 1954 - Sep lastSun 2:00 0 S + Rule Chicago 1955 1966 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24 ++Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1920 + -6:00 Chicago C%sT 1936 Mar 1 2:00 + -5:00 - EST 1936 Nov 15 2:00 +@@ -471,7 +471,7 @@ Zone America/Chicago -5:50:36 - LMT 1883 Nov 18 12:09:24 + -6:00 Chicago C%sT 1967 + -6:00 US C%sT + # Oliver County, ND switched from mountain to central time on 1992-10-25. +-Zone America/North_Dakota/Center -6:45:12 - LMT 1883 Nov 18 12:14:48 ++Zone America/North_Dakota/Center -6:45:12 - LMT 1883 Nov 18 19:00u + -7:00 US M%sT 1992 Oct 25 2:00 + -6:00 US C%sT + # Morton County, ND, switched from mountain to central time on +@@ -481,7 +481,7 @@ Zone America/North_Dakota/Center -6:45:12 - LMT 1883 Nov 18 12:14:48 + # Jones, Mellette, and Todd Counties in South Dakota; + # but in practice these other counties were already observing central time. + # See . +-Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21 ++Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 19:00u + -7:00 US M%sT 2003 Oct 26 2:00 + -6:00 US C%sT + +@@ -498,7 +498,7 @@ Zone America/North_Dakota/New_Salem -6:45:39 - LMT 1883 Nov 18 12:14:21 + # largest city in Mercer County). Google Maps places Beulah's city hall + # at 47° 15' 51" N, 101° 46' 40" W, which yields an offset of 6h47'07". + +-Zone America/North_Dakota/Beulah -6:47:07 - LMT 1883 Nov 18 12:12:53 ++Zone America/North_Dakota/Beulah -6:47:07 - LMT 1883 Nov 18 19:00u + -7:00 US M%sT 2010 Nov 7 2:00 + -6:00 US C%sT + +@@ -530,7 +530,7 @@ Rule Denver 1921 only - May 22 2:00 0 S + Rule Denver 1965 1966 - Apr lastSun 2:00 1:00 D + Rule Denver 1965 1966 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Denver -6:59:56 - LMT 1883 Nov 18 12:00:04 ++Zone America/Denver -6:59:56 - LMT 1883 Nov 18 19:00u + -7:00 US M%sT 1920 + -7:00 Denver M%sT 1942 + -7:00 US M%sT 1946 +@@ -583,7 +583,7 @@ Rule CA 1950 1966 - Apr lastSun 1:00 1:00 D + Rule CA 1950 1961 - Sep lastSun 2:00 0 S + Rule CA 1962 1966 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Los_Angeles -7:52:58 - LMT 1883 Nov 18 12:07:02 ++Zone America/Los_Angeles -7:52:58 - LMT 1883 Nov 18 20:00u + -8:00 US P%sT 1946 + -8:00 CA P%sT 1967 + -8:00 US P%sT +@@ -845,7 +845,7 @@ Zone Pacific/Honolulu -10:31:26 - LMT 1896 Jan 13 12:00 + # Go with the Arizona State Library instead. + + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Phoenix -7:28:18 - LMT 1883 Nov 18 11:31:42 ++Zone America/Phoenix -7:28:18 - LMT 1883 Nov 18 19:00u + -7:00 US M%sT 1944 Jan 1 0:01 + -7:00 - MST 1944 Apr 1 0:01 + -7:00 US M%sT 1944 Oct 1 0:01 +@@ -873,7 +873,7 @@ Link America/Phoenix America/Creston + # switched four weeks late in 1974. + # + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Boise -7:44:49 - LMT 1883 Nov 18 12:15:11 ++Zone America/Boise -7:44:49 - LMT 1883 Nov 18 20:00u + -8:00 US P%sT 1923 May 13 2:00 + -7:00 US M%sT 1974 + -7:00 - MST 1974 Feb 3 2:00 +@@ -945,7 +945,7 @@ Rule Indianapolis 1941 only - Jun 22 2:00 1:00 D + Rule Indianapolis 1941 1954 - Sep lastSun 2:00 0 S + Rule Indianapolis 1946 1954 - Apr lastSun 2:00 1:00 D + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Indianapolis -5:44:38 - LMT 1883 Nov 18 12:15:22 ++Zone America/Indiana/Indianapolis -5:44:38 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1920 + -6:00 Indianapolis C%sT 1942 + -6:00 US C%sT 1946 +@@ -965,7 +965,7 @@ Rule Marengo 1951 only - Sep lastSun 2:00 0 S + Rule Marengo 1954 1960 - Apr lastSun 2:00 1:00 D + Rule Marengo 1954 1960 - Sep lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Marengo -5:45:23 - LMT 1883 Nov 18 12:14:37 ++Zone America/Indiana/Marengo -5:45:23 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1951 + -6:00 Marengo C%sT 1961 Apr 30 2:00 + -5:00 - EST 1969 +@@ -989,7 +989,7 @@ Rule Vincennes 1960 only - Oct lastSun 2:00 0 S + Rule Vincennes 1961 only - Sep lastSun 2:00 0 S + Rule Vincennes 1962 1963 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Vincennes -5:50:07 - LMT 1883 Nov 18 12:09:53 ++Zone America/Indiana/Vincennes -5:50:07 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1946 + -6:00 Vincennes C%sT 1964 Apr 26 2:00 + -5:00 - EST 1969 +@@ -1009,7 +1009,7 @@ Rule Perry 1955 1960 - Sep lastSun 2:00 0 S + Rule Perry 1956 1963 - Apr lastSun 2:00 1:00 D + Rule Perry 1961 1963 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Tell_City -5:47:03 - LMT 1883 Nov 18 12:12:57 ++Zone America/Indiana/Tell_City -5:47:03 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1946 + -6:00 Perry C%sT 1964 Apr 26 2:00 + -5:00 - EST 1967 Oct 29 2:00 +@@ -1026,7 +1026,7 @@ Rule Pike 1955 1960 - Sep lastSun 2:00 0 S + Rule Pike 1956 1964 - Apr lastSun 2:00 1:00 D + Rule Pike 1961 1964 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Petersburg -5:49:07 - LMT 1883 Nov 18 12:10:53 ++Zone America/Indiana/Petersburg -5:49:07 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1955 + -6:00 Pike C%sT 1965 Apr 25 2:00 + -5:00 - EST 1966 Oct 30 2:00 +@@ -1048,7 +1048,7 @@ Rule Starke 1955 1956 - Oct lastSun 2:00 0 S + Rule Starke 1957 1958 - Sep lastSun 2:00 0 S + Rule Starke 1959 1961 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Knox -5:46:30 - LMT 1883 Nov 18 12:13:30 ++Zone America/Indiana/Knox -5:46:30 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1947 + -6:00 Starke C%sT 1962 Apr 29 2:00 + -5:00 - EST 1963 Oct 27 2:00 +@@ -1064,7 +1064,7 @@ Rule Pulaski 1946 1954 - Sep lastSun 2:00 0 S + Rule Pulaski 1955 1956 - Oct lastSun 2:00 0 S + Rule Pulaski 1957 1960 - Sep lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Winamac -5:46:25 - LMT 1883 Nov 18 12:13:35 ++Zone America/Indiana/Winamac -5:46:25 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1946 + -6:00 Pulaski C%sT 1961 Apr 30 2:00 + -5:00 - EST 1969 +@@ -1075,7 +1075,7 @@ Zone America/Indiana/Winamac -5:46:25 - LMT 1883 Nov 18 12:13:35 + # + # Switzerland County, Indiana, did not observe DST from 1973 through 2005. + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Indiana/Vevay -5:40:16 - LMT 1883 Nov 18 12:19:44 ++Zone America/Indiana/Vevay -5:40:16 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1954 Apr 25 2:00 + -5:00 - EST 1969 + -5:00 US E%sT 1973 +@@ -1111,7 +1111,7 @@ Rule Louisville 1950 1961 - Apr lastSun 2:00 1:00 D + Rule Louisville 1950 1955 - Sep lastSun 2:00 0 S + Rule Louisville 1956 1961 - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] +-Zone America/Kentucky/Louisville -5:43:02 - LMT 1883 Nov 18 12:16:58 ++Zone America/Kentucky/Louisville -5:43:02 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1921 + -6:00 Louisville C%sT 1942 + -6:00 US C%sT 1946 +@@ -1145,7 +1145,7 @@ Zone America/Kentucky/Louisville -5:43:02 - LMT 1883 Nov 18 12:16:58 + # Federal Register 65, 160 (2000-08-17), pp 50154-50158. + # https://www.gpo.gov/fdsys/pkg/FR-2000-08-17/html/00-20854.htm + # +-Zone America/Kentucky/Monticello -5:39:24 - LMT 1883 Nov 18 12:20:36 ++Zone America/Kentucky/Monticello -5:39:24 - LMT 1883 Nov 18 18:00u + -6:00 US C%sT 1946 + -6:00 - CST 1968 + -6:00 US C%sT 2000 Oct 29 2:00 +@@ -2640,6 +2640,8 @@ Zone America/Dawson -9:17:40 - LMT 1900 Aug 20 + # longitude they are located at. + + # Rule NAME FROM TO - IN ON AT SAVE LETTER/S ++Rule Mexico 1931 only - May 1 23:00 1:00 D ++Rule Mexico 1931 only - Oct 1 0:00 0 S + Rule Mexico 1939 only - Feb 5 0:00 1:00 D + Rule Mexico 1939 only - Jun 25 0:00 0 S + Rule Mexico 1940 only - Dec 9 0:00 1:00 D +@@ -2656,13 +2658,13 @@ Rule Mexico 2002 max - Apr Sun>=1 2:00 1:00 D + Rule Mexico 2002 max - Oct lastSun 2:00 0 S + # Zone NAME STDOFF RULES FORMAT [UNTIL] + # Quintana Roo; represented by Cancún +-Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 0:12:56 ++Zone America/Cancun -5:47:04 - LMT 1922 Jan 1 6:00u + -6:00 - CST 1981 Dec 23 + -5:00 Mexico E%sT 1998 Aug 2 2:00 + -6:00 Mexico C%sT 2015 Feb 1 2:00 + -5:00 - EST + # Campeche, Yucatán; represented by Mérida +-Zone America/Merida -5:58:28 - LMT 1922 Jan 1 0:01:32 ++Zone America/Merida -5:58:28 - LMT 1922 Jan 1 6:00u + -6:00 - CST 1981 Dec 23 + -5:00 - EST 1982 Dec 2 + -6:00 Mexico C%sT +@@ -2676,23 +2678,21 @@ Zone America/Merida -5:58:28 - LMT 1922 Jan 1 0:01:32 + # See: Inicia mañana Horario de Verano en zona fronteriza, El Universal, + # 2016-03-12 + # http://www.eluniversal.com.mx/articulo/estados/2016/03/12/inicia-manana-horario-de-verano-en-zona-fronteriza +-Zone America/Matamoros -6:40:00 - LMT 1921 Dec 31 23:20:00 ++Zone America/Matamoros -6:30:00 - LMT 1922 Jan 1 6:00u + -6:00 - CST 1988 + -6:00 US C%sT 1989 + -6:00 Mexico C%sT 2010 + -6:00 US C%sT + # Durango; Coahuila, Nuevo León, Tamaulipas (away from US border) +-Zone America/Monterrey -6:41:16 - LMT 1921 Dec 31 23:18:44 ++Zone America/Monterrey -6:41:16 - LMT 1922 Jan 1 6:00u + -6:00 - CST 1988 + -6:00 US C%sT 1989 + -6:00 Mexico C%sT + # Central Mexico +-Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 0:23:24 ++Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 Mexico C%sT 2001 Sep 30 2:00 + -6:00 - CST 2002 Feb 20 + -6:00 Mexico C%sT +@@ -2700,35 +2700,29 @@ Zone America/Mexico_City -6:36:36 - LMT 1922 Jan 1 0:23:24 + # This includes the municipalities of Janos, Ascensión, Juárez, Guadalupe, + # Práxedis G Guerrero, Coyame del Sotol, Ojinaga, and Manuel Benavides. + # (See the 2016-03-12 El Universal source mentioned above.) +-Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 0:02:20 ++Zone America/Ojinaga -6:57:40 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1996 + -6:00 Mexico C%sT 1998 + -6:00 - CST 1998 Apr Sun>=1 3:00 + -7:00 Mexico M%sT 2010 + -7:00 US M%sT + # Chihuahua (away from US border) +-Zone America/Chihuahua -7:04:20 - LMT 1921 Dec 31 23:55:40 ++Zone America/Chihuahua -7:04:20 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1996 + -6:00 Mexico C%sT 1998 + -6:00 - CST 1998 Apr Sun>=1 3:00 + -7:00 Mexico M%sT + # Sonora +-Zone America/Hermosillo -7:23:52 - LMT 1921 Dec 31 23:36:08 ++Zone America/Hermosillo -7:23:52 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1942 Apr 24 + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1970 +@@ -2763,24 +2757,20 @@ Zone America/Hermosillo -7:23:52 - LMT 1921 Dec 31 23:36:08 + # Use "Bahia_Banderas" to keep the name to fourteen characters. + + # Mazatlán +-Zone America/Mazatlan -7:05:40 - LMT 1921 Dec 31 23:54:20 ++Zone America/Mazatlan -7:05:40 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1942 Apr 24 + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1970 + -7:00 Mexico M%sT + + # Bahía de Banderas +-Zone America/Bahia_Banderas -7:01:00 - LMT 1921 Dec 31 23:59:00 ++Zone America/Bahia_Banderas -7:01:00 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1927 Jun 10 23:00 + -6:00 - CST 1930 Nov 15 +- -7:00 - MST 1931 May 1 23:00 +- -6:00 - CST 1931 Oct +- -7:00 - MST 1932 Apr 1 ++ -7:00 Mexico M%sT 1932 Apr 1 + -6:00 - CST 1942 Apr 24 + -7:00 - MST 1949 Jan 14 + -8:00 - PST 1970 +@@ -2788,7 +2778,7 @@ Zone America/Bahia_Banderas -7:01:00 - LMT 1921 Dec 31 23:59:00 + -6:00 Mexico C%sT + + # Baja California +-Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 0:11:56 ++Zone America/Tijuana -7:48:04 - LMT 1922 Jan 1 7:00u + -7:00 - MST 1924 + -8:00 - PST 1927 Jun 10 23:00 + -7:00 - MST 1930 Nov 15 +-- +1.8.3.1 diff --git a/8296480-Fix-the-problem-that-the-TestPolicy.java-cas.patch b/8296480-Fix-the-problem-that-the-TestPolicy.java-cas.patch new file mode 100644 index 0000000..7d1be49 --- /dev/null +++ b/8296480-Fix-the-problem-that-the-TestPolicy.java-cas.patch @@ -0,0 +1,42 @@ +From 6d1c5b1ee82b2b2481a16f3510078fdc7ddc08f9 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Tue, 15 Nov 2022 11:26:33 +0800 +Subject: [PATCH 04/33] 8296480: Fix the problem that the TestPolicy.java case + fails because the certificate expires. +--- + jdk/test/java/security/cert/pkix/policyChanges/TestPolicy.java | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/jdk/test/java/security/cert/pkix/policyChanges/TestPolicy.java b/jdk/test/java/security/cert/pkix/policyChanges/TestPolicy.java +index a92eee2..b37debf 100644 +--- a/jdk/test/java/security/cert/pkix/policyChanges/TestPolicy.java ++++ b/jdk/test/java/security/cert/pkix/policyChanges/TestPolicy.java +@@ -1,5 +1,5 @@ + /* +- * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. ++ * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it +@@ -34,6 +34,7 @@ + */ + + import java.io.*; ++import java.text.DateFormat; + import java.util.*; + + import java.security.Security; +@@ -97,6 +98,10 @@ public class TestPolicy { + params.setRevocationEnabled(false); + params.setInitialPolicies(testCase.initialPolicies); + ++ // Certs expired on 7th Nov 2022 ++ params.setDate(DateFormat.getDateInstance(DateFormat.MEDIUM, ++ Locale.US).parse("June 01, 2022")); ++ + CertPath path = factory.generateCertPath(Arrays.asList(new X509Certificate[] {ee, ca})); + + PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)validator.validate(path, params); +-- +1.8.3.1 + diff --git a/8296485-BuildEEBasicConstraints.java-test-fails-with.patch b/8296485-BuildEEBasicConstraints.java-test-fails-with.patch new file mode 100644 index 0000000..b641e88 --- /dev/null +++ b/8296485-BuildEEBasicConstraints.java-test-fails-with.patch @@ -0,0 +1,39 @@ +From b8aedd236ca707cfc15eb5daf91aab697a8014ed Mon Sep 17 00:00:00 2001 +From: eapen +Date: Wed, 23 Nov 2022 08:31:14 +0800 +Subject: [PATCH 06/33] I68TO2: 8296485: BuildEEBasicConstraints.java test fails with + SunCertPathBuilderException +--- + .../CertPathBuilder/targetConstraints/BuildEEBasicConstraints.java | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/jdk/test/java/security/cert/CertPathBuilder/targetConstraints/BuildEEBasicConstraints.java b/jdk/test/java/security/cert/CertPathBuilder/targetConstraints/BuildEEBasicConstraints.java +index 6be5562..44926d2 100644 +--- a/jdk/test/java/security/cert/CertPathBuilder/targetConstraints/BuildEEBasicConstraints.java ++++ b/jdk/test/java/security/cert/CertPathBuilder/targetConstraints/BuildEEBasicConstraints.java +@@ -46,9 +46,11 @@ import java.security.cert.PKIXCertPathBuilderResult; + import java.security.cert.TrustAnchor; + import java.security.cert.X509Certificate; + import java.security.cert.X509CertSelector; ++import java.text.DateFormat; + import java.util.ArrayList; + import java.util.Collections; + import java.util.List; ++import java.util.Locale; + + public final class BuildEEBasicConstraints { + +@@ -65,6 +67,11 @@ public final class BuildEEBasicConstraints { + PKIXBuilderParameters params = new PKIXBuilderParameters + (Collections.singleton(anchor), sel); + params.setRevocationEnabled(false); ++ ++ // Certs expired on 7th Nov 2022 ++ params.setDate(DateFormat.getDateInstance(DateFormat.MEDIUM, ++ Locale.US).parse("June 01, 2022")); ++ + X509Certificate eeCert = CertUtils.getCertFromFile("ee.cer"); + X509Certificate caCert = CertUtils.getCertFromFile("ca.cer"); + ArrayList certs = new ArrayList(); +-- +1.8.3.1 diff --git a/Fix-AsyncGCLog-s-content-consistent-bug.patch b/Fix-AsyncGCLog-s-content-consistent-bug.patch new file mode 100644 index 0000000..bf8229d --- /dev/null +++ b/Fix-AsyncGCLog-s-content-consistent-bug.patch @@ -0,0 +1,38 @@ +From a9c12b1881b227e537089c14bfcc3a00cfc7c1ac Mon Sep 17 00:00:00 2001 +From: eapen +Date: Mon, 19 Dec 2022 21:12:55 +0800 +Subject: [PATCH 33/33] I68TO2: Fix AsyncGCLog's content consistent bug +--- + hotspot/src/share/vm/runtime/java.cpp | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp +index e2194dd..5b82a7a 100644 +--- a/hotspot/src/share/vm/runtime/java.cpp ++++ b/hotspot/src/share/vm/runtime/java.cpp +@@ -516,11 +516,6 @@ void before_exit(JavaThread * thread) { + // Stop concurrent GC threads + Universe::heap()->stop(); + +- // Stop async log writer thread +- if (UseAsyncGCLog) { +- AsyncLogWriter::instance()->stop(); +- } +- + // Print GC/heap related information. + if (PrintGCDetails) { + Universe::print(); +@@ -584,6 +579,11 @@ void before_exit(JavaThread * thread) { + } + } + ++ // Stop async log writer thread ++ if (UseAsyncGCLog) { ++ AsyncLogWriter::instance()->stop(); ++ } ++ + #undef BEFORE_EXIT_NOT_RUN + #undef BEFORE_EXIT_RUNNING + #undef BEFORE_EXIT_DONE +-- +1.8.3.1 diff --git a/Fix-compactibleFreeListSpace-block_size_no_stall-cra.patch b/Fix-compactibleFreeListSpace-block_size_no_stall-cra.patch new file mode 100644 index 0000000..d231dc3 --- /dev/null +++ b/Fix-compactibleFreeListSpace-block_size_no_stall-cra.patch @@ -0,0 +1,30 @@ +From 3d9fd51e13f76861e21293143b23c6936e030dfc Mon Sep 17 00:00:00 2001 +From: eapen +Date: Wed, 14 Dec 2022 16:54:06 +0800 +Subject: [PATCH 16/33] I68TO2: Fix compactibleFreeListSpace::block_size_no_stall crash + when use JMap parallel inspection of CMS GC +--- + .../concurrentMarkSweep/concurrentMarkSweepGeneration.cpp | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +index d31f9a5..c923e85 100644 +--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp ++++ b/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp +@@ -2896,10 +2896,11 @@ void ConcurrentMarkSweepGeneration::object_iterate_block(ObjectClosure *cl, size + } + } + } +- if (prev_obj < span.end()) { +- HeapWord *cur, *limit; ++ HeapWord *limit = MIN2(cmsSpace()->end(), span.end()); ++ if (prev_obj < limit) { ++ HeapWord *cur; + size_t curSize; +- for (cur = prev_obj, limit = span.end(); cur < limit; cur += curSize) { ++ for (cur = prev_obj; cur < limit; cur += curSize) { + curSize = cmsSpace()->block_size_no_stall(cur, _collector); + if (curSize == 0) { + break; +-- +1.8.3.1 diff --git a/Fix-the-crash-that-occurs-when-the-process-exits-due.patch b/Fix-the-crash-that-occurs-when-the-process-exits-due.patch new file mode 100644 index 0000000..47904e8 --- /dev/null +++ b/Fix-the-crash-that-occurs-when-the-process-exits-due.patch @@ -0,0 +1,116 @@ +From e635dce083e968ed54f8c7b7b059ce8c3c9ee717 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Fri, 16 Dec 2022 16:00:25 +0800 +Subject: [PATCH 32/33] I68TO2: Fix the crash that occurs when the process exits due to + the mixed use of GCTrimNativeHeap and UseAsyncGCLog +--- + hotspot/src/share/vm/runtime/java.cpp | 6 +++++ + hotspot/src/share/vm/runtime/logAsyncWriter.cpp | 35 ++++++++++++++++++++++++- + hotspot/src/share/vm/runtime/logAsyncWriter.hpp | 4 +++ + 3 files changed, 44 insertions(+), 1 deletion(-) + +diff --git a/hotspot/src/share/vm/runtime/java.cpp b/hotspot/src/share/vm/runtime/java.cpp +index 54b980d..e2194dd 100644 +--- a/hotspot/src/share/vm/runtime/java.cpp ++++ b/hotspot/src/share/vm/runtime/java.cpp +@@ -54,6 +54,7 @@ + #include "runtime/init.hpp" + #include "runtime/interfaceSupport.hpp" + #include "runtime/java.hpp" ++#include "runtime/logAsyncWriter.hpp" + #include "runtime/memprofiler.hpp" + #include "runtime/sharedRuntime.hpp" + #include "runtime/statSampler.hpp" +@@ -515,6 +516,11 @@ void before_exit(JavaThread * thread) { + // Stop concurrent GC threads + Universe::heap()->stop(); + ++ // Stop async log writer thread ++ if (UseAsyncGCLog) { ++ AsyncLogWriter::instance()->stop(); ++ } ++ + // Print GC/heap related information. + if (PrintGCDetails) { + Universe::print(); +diff --git a/hotspot/src/share/vm/runtime/logAsyncWriter.cpp b/hotspot/src/share/vm/runtime/logAsyncWriter.cpp +index 750a23f..7722020 100644 +--- a/hotspot/src/share/vm/runtime/logAsyncWriter.cpp ++++ b/hotspot/src/share/vm/runtime/logAsyncWriter.cpp +@@ -63,7 +63,7 @@ void AsyncLogWriter::enqueue(const char* msg) { + AsyncLogWriter::AsyncLogWriter() + : NamedThread(), + _lock(1), _sem(0), _io_sem(1), +- _initialized(false), ++ _initialized(false),_should_terminate(false),_has_terminated(false), + _buffer_max_size(AsyncLogBufferSize / sizeof(AsyncLogMessage)) { + if (os::create_thread(this, os::asynclog_thread)) { + _initialized = true; +@@ -124,6 +124,10 @@ void AsyncLogWriter::run() { + // The value of a semphore cannot be negative. Therefore, the current thread falls asleep + // when its value is zero. It will be waken up when new messages are enqueued. + _sem.wait(); ++ if (_should_terminate) { ++ terminate(); ++ break; ++ } + write(); + } + } +@@ -162,3 +166,32 @@ void AsyncLogWriter::print_on(outputStream* st) const{ + Thread::print_on(st); + st->cr(); + } ++ ++void AsyncLogWriter::stop() { ++ { ++ MutexLockerEx ml(Terminator_lock); ++ _should_terminate = true; ++ } ++ { ++ _sem.signal(); ++ } ++ { ++ MutexLockerEx ml(Terminator_lock); ++ while (!_has_terminated) { ++ Terminator_lock->wait(); ++ } ++ } ++} ++ ++void AsyncLogWriter::terminate() { ++ // Signal that it is terminated ++ { ++ MutexLockerEx mu(Terminator_lock, ++ Mutex::_no_safepoint_check_flag); ++ _has_terminated = true; ++ Terminator_lock->notify(); ++ } ++ ++ // Thread destructor usually does this.. ++ ThreadLocalStorage::set_thread(NULL); ++} +diff --git a/hotspot/src/share/vm/runtime/logAsyncWriter.hpp b/hotspot/src/share/vm/runtime/logAsyncWriter.hpp +index 5242426..54e5d48 100644 +--- a/hotspot/src/share/vm/runtime/logAsyncWriter.hpp ++++ b/hotspot/src/share/vm/runtime/logAsyncWriter.hpp +@@ -136,6 +136,8 @@ class AsyncLogWriter : public NamedThread { + Semaphore _io_sem; + + volatile bool _initialized; ++ volatile bool _should_terminate; ++ volatile bool _has_terminated; + AsyncLogBuffer _buffer; + + const size_t _buffer_max_size; +@@ -153,6 +155,8 @@ class AsyncLogWriter : public NamedThread { + static void flush(); + // Printing + void print_on(outputStream* st) const; ++ void stop(); ++ void terminate(); + + }; + +-- +1.8.3.1 diff --git a/Print-class-loading-details-when-enable-TraceClassLo.patch b/Print-class-loading-details-when-enable-TraceClassLo.patch new file mode 100644 index 0000000..594034d --- /dev/null +++ b/Print-class-loading-details-when-enable-TraceClassLo.patch @@ -0,0 +1,67 @@ +From 3b427b4702ac1ccdfa47fc46522fc06884abf394 Mon Sep 17 00:00:00 2001 +From: eapen +Date: Fri, 16 Dec 2022 09:23:41 +0800 +Subject: [PATCH 24/33] I68TO2: Print class loading details when enable + TraceClassLoading +--- + hotspot/src/share/vm/classfile/classFileParser.cpp | 25 +++++++++++++++++++--- + hotspot/src/share/vm/runtime/globals.hpp | 8 +++++++ + 2 files changed, 30 insertions(+), 3 deletions(-) + +diff --git a/hotspot/src/share/vm/classfile/classFileParser.cpp b/hotspot/src/share/vm/classfile/classFileParser.cpp +index ae91995..3ec6aec 100644 +--- a/hotspot/src/share/vm/classfile/classFileParser.cpp ++++ b/hotspot/src/share/vm/classfile/classFileParser.cpp +@@ -4323,9 +4323,28 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, + if (TraceClassLoading) { + ResourceMark rm; + // print in a single call to reduce interleaving of output +- if (cfs->source() != NULL) { +- tty->print("[Loaded %s from %s]\n", this_klass->external_name(), +- cfs->source()); ++ const char* source = cfs->source(); ++ if (source != NULL && PrintClassLoadingDetails) { ++ tty->date_stamp(true); ++ OSThread* osThread = THREAD->osthread(); ++ if (osThread != NULL) { ++ tty->print("%d ", osThread->thread_id()); ++ } ++ const char* loader_name = class_loader.is_null() ++ ? "bootstrap" ++ : InstanceKlass::cast(class_loader->klass())->external_name(); ++ const char* klass_name = this_klass->external_name(); ++ tty->print(" [Loaded %s from %s by classloader %s]\n", klass_name, ++ source, loader_name); ++ if (PrintThreadStackOnLoadingClass != NULL && klass_name != NULL && ++ strstr(klass_name, PrintThreadStackOnLoadingClass) && THREAD->is_Java_thread()) { ++ JavaThread* javaThread = ((JavaThread*) THREAD); ++ javaThread->print_on(tty); ++ javaThread->print_stack_on(tty); ++ } ++ } else if (source != NULL) { ++ tty->print("[Loaded %s from %s]\n", this_klass->external_name(), ++ source); + } else if (class_loader.is_null()) { + Klass* caller = + THREAD->is_Java_thread() +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index d1e3cda..14c3c89 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -951,6 +951,14 @@ class CommandLineFlags { + product(ccstrlist, OnOutOfMemoryError, "", \ + "Run user-defined commands on first java.lang.OutOfMemoryError") \ + \ ++ manageable(bool, PrintClassLoadingDetails, false, \ ++ "Print class loading details (including date stamps, thread id " \ ++ "and effective class loaders) when enable TraceClassLoading") \ ++ \ ++ manageable(ccstr, PrintThreadStackOnLoadingClass, NULL, \ ++ "Print thread stack when the specified class is loaded when " \ ++ "enable PrintClassLoadingDetails") \ ++ \ + manageable(bool, HeapDumpBeforeFullGC, false, \ + "Dump heap to file before any major stop-the-world GC") \ + \ +-- +1.8.3.1 diff --git a/fix-the-length-value-of-ciBlock-in-ciMethodBlocks.cp.patch b/fix-the-length-value-of-ciBlock-in-ciMethodBlocks.cp.patch new file mode 100644 index 0000000..d149085 --- /dev/null +++ b/fix-the-length-value-of-ciBlock-in-ciMethodBlocks.cp.patch @@ -0,0 +1,23 @@ +From 102b398cc59e95cb4f5327b9c8fc9a3c5594acce Mon Sep 17 00:00:00 2001 +From: eapen +Date: Tue, 29 Nov 2022 09:23:01 +0800 +Subject: [PATCH 29/33] I68TO2: fix the length value of ciBlock in ciMethodBlocks.cpp +--- + hotspot/src/share/vm/ci/ciMethodBlocks.cpp | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp +index 614e75d..3ce828e 100644 +--- a/hotspot/src/share/vm/ci/ciMethodBlocks.cpp ++++ b/hotspot/src/share/vm/ci/ciMethodBlocks.cpp +@@ -372,7 +372,7 @@ static const char *flagnames[] = { + + void ciBlock::dump() { + tty->print(" [%d .. %d), {", _start_bci, _limit_bci); +- for (int i = 0; i < 8; i++) { ++ for (int i = 0; i < 7; i++) { + if ((_flags & (1 << i)) != 0) { + tty->print(" %s", flagnames[i]); + } +-- +1.8.3.1 diff --git a/openjdk-1.8.0.spec b/openjdk-1.8.0.spec index 0a9fd88..4c616d9 100644 --- a/openjdk-1.8.0.spec +++ b/openjdk-1.8.0.spec @@ -916,7 +916,7 @@ Provides: java-%{javaver}-%{origin}-accessibility%{?1} = %{epoch}:%{version}-%{r Name: java-%{javaver}-%{origin} Version: %{javaver}.%{updatever}.%{buildver} -Release: 4 +Release: 5 # java-1.5.0-ibm from jpackage.org set Epoch to 1 for unknown reasons # and this change was brought into RHEL-4. java-1.5.0-ibm packages # also included the epoch in their virtual provides. This created a @@ -1153,6 +1153,35 @@ Patch264: 8287109-Distrust-failed-with-CertificateExpired.patch Patch265: cve-2022-37434-Fix-a-bug-when-getting-a-gzip-header-extra-field-with-inflate.patch Patch266: 8065895-Synchronous-signals-during-error-reporting-may-terminate-or-hang-vm-process.patch Patch267: Huawei-fix-windows-build-Dynamic-CDS-failure.patch +Patch268: 8296480-Fix-the-problem-that-the-TestPolicy.java-cas.patch +Patch269: 8296485-BuildEEBasicConstraints.java-test-fails-with.patch +Patch270: 8294357-tz-Update-Timezone-Data-to-2022d.patch +Patch271: 8296241-tz-Update-Timezone-Data-to-2022e.patch +Patch272: 8296108-tz-Update-Timezone-Data-to-2022f.patch +Patch273: 8257695-linux-Add-process-memory-information-to-hs-e.patch +Patch274: 8261167-print_process_memory_info-add-a-close-call-a.patch +Patch275: 8268893-jcmd-to-trim-the-glibc-heap.patch +Patch276: 8263185-Mallinfo-deprecated-in-glibc-2.33.patch +Patch277: 8293114-GC-should-trim-the-native-heap-and-bug-fix.patch +Patch278: 8275775-Add-jcmd-VM.classes-to-print-details-of-all-.patch +Patch279: Fix-compactibleFreeListSpace-block_size_no_stall-cra.patch +Patch280: 8203682-Add-jcmd-VM.classloaders-command-to-print-ou.patch +Patch281: 8229517-Support-for-optional-asynchronous-buffered-l.patch +Patch282: 8189688-NMT-Report-per-class-load-metadata-informati.patch +Patch283: 8219584-Try-to-dump-error-file-by-thread-which-cause.patch +Patch284: 8204595-add-more-thread-related-system-settings-info.patch +Patch285: 8198553-jcmd-separate-Metaspace-statistics-from-NMT.patch +Patch286: 8242181-Show-source-information-when-printing-native.patch +Patch287: Print-class-loading-details-when-enable-TraceClassLo.patch +Patch288: 8200720-Print-additional-information-in-thread-dump-.patch +Patch289: support-numactl-for-hadoop-yarn.patch +Patch290: 8232069-enable-shutdown-UseCompressedClassPointers-U.patch +Patch291: 8065402-G1-does-not-expand-marking-stack-when-mark-s.patch +Patch292: fix-the-length-value-of-ciBlock-in-ciMethodBlocks.cp.patch +Patch293: 8140594-Various-minor-code-improvements-compiler.patch +Patch294: Fix-the-crash-that-occurs-when-the-process-exits-due.patch +Patch295: Fix-AsyncGCLog-s-content-consistent-bug.patch + ############################################# # @@ -1646,6 +1675,34 @@ pushd %{top_level_dir_name} %patch265 -p1 %patch266 -p1 %patch267 -p1 +%patch268 -p1 +%patch269 -p1 +%patch270 -p1 +%patch271 -p1 +%patch272 -p1 +%patch273 -p1 +%patch274 -p1 +%patch275 -p1 +%patch276 -p1 +%patch277 -p1 +%patch278 -p1 +%patch279 -p1 +%patch280 -p1 +%patch281 -p1 +%patch282 -p1 +%patch283 -p1 +%patch284 -p1 +%patch285 -p1 +%patch286 -p1 +%patch287 -p1 +%patch288 -p1 +%patch289 -p1 +%patch290 -p1 +%patch291 -p1 +%patch292 -p1 +%patch293 -p1 +%patch294 -p1 +%patch295 -p1 popd # System library fixes @@ -2270,6 +2327,36 @@ cjc.mainProgram(arg) %endif %changelog +* Wed Jan 11 2023 eapen - 1:1.8.0.352-b08.5 +- add 8296480-Fix-the-problem-that-the-TestPolicy.java-cas.patch +- add 8296485-BuildEEBasicConstraints.java-test-fails-with.patch +- add 8294357-tz-Update-Timezone-Data-to-2022d.patch +- add 8296241-tz-Update-Timezone-Data-to-2022e.patch +- add 8296108-tz-Update-Timezone-Data-to-2022f.patch +- add 8257695-linux-Add-process-memory-information-to-hs-e.patch +- add 8261167-print_process_memory_info-add-a-close-call-a.patch +- add 8268893-jcmd-to-trim-the-glibc-heap.patch +- add 8263185-Mallinfo-deprecated-in-glibc-2.33.patch +- add 8293114-GC-should-trim-the-native-heap-and-bug-fix.patch +- add 8275775-Add-jcmd-VM.classes-to-print-details-of-all-.patch +- add Fix-compactibleFreeListSpace-block_size_no_stall-cra.patch +- add 8203682-Add-jcmd-VM.classloaders-command-to-print-ou.patch +- add 8229517-Support-for-optional-asynchronous-buffered-l.patch +- add 8189688-NMT-Report-per-class-load-metadata-informati.patch +- add 8219584-Try-to-dump-error-file-by-thread-which-cause.patch +- add 8204595-add-more-thread-related-system-settings-info.patch +- add 8198553-jcmd-separate-Metaspace-statistics-from-NMT.patch +- add 8242181-Show-source-information-when-printing-native.patch +- add Print-class-loading-details-when-enable-TraceClassLo.patch +- add 8200720-Print-additional-information-in-thread-dump-.patch +- add support-numactl-for-hadoop-yarn.patch +- add 8232069-enable-shutdown-UseCompressedClassPointers-U.patch +- add 8065402-G1-does-not-expand-marking-stack-when-mark-s.patch +- add fix-the-length-value-of-ciBlock-in-ciMethodBlocks.cp.patch +- add 8140594-Various-minor-code-improvements-compiler.patch +- add Fix-the-crash-that-occurs-when-the-process-exits-due.patch +- add Fix-AsyncGCLog-s-content-consistent-bug.patch + * Tue Oct 25 2022 kuenking111 - 1:1.8.0.352-b08.4 - add Huawei-fix-windows-build-Dynamic-CDS-failure.patch diff --git a/support-numactl-for-hadoop-yarn.patch b/support-numactl-for-hadoop-yarn.patch new file mode 100644 index 0000000..80c7d61 --- /dev/null +++ b/support-numactl-for-hadoop-yarn.patch @@ -0,0 +1,599 @@ +From db8bc872fb7a132cb3c2363dcb3a7aa8b0a5827e Mon Sep 17 00:00:00 2001 +From: eapen +Date: Mon, 25 Jul 2022 16:41:24 +0800 +Subject: [PATCH 26/33] I68TO2: support numactl for hadoop yarn +--- + hotspot/make/aix/makefiles/mapfile-vers-debug | 1 + + hotspot/make/aix/makefiles/mapfile-vers-product | 1 + + hotspot/make/linux/makefiles/mapfile-vers-debug | 1 + + hotspot/make/linux/makefiles/mapfile-vers-product | 1 + + hotspot/make/solaris/makefiles/mapfile-vers | 1 + + hotspot/make/windows/jvmexp.lcf | 1 + + hotspot/make/windows/jvmexp_g.lcf | 1 + + hotspot/make/windows/makefiles/vm.make | 1 + + hotspot/src/os/linux/vm/os_linux.cpp | 91 +++++++++++++++++++ + hotspot/src/os/linux/vm/os_linux.hpp | 51 +++++++++++ + hotspot/src/share/vm/prims/jni.cpp | 6 ++ + hotspot/src/share/vm/prims/jni.h | 3 + + hotspot/src/share/vm/runtime/globals.hpp | 13 +++ + .../runtime/containers/docker/CPUSetsReader.java | 9 ++ + .../runtime/containers/docker/TestNUMANodes.java | 102 +++++++++++++++++++++ + jdk/src/share/bin/java.c | 2 + + jdk/src/share/bin/java.h | 3 + + jdk/src/share/javavm/export/jni.h | 3 + + jdk/src/solaris/bin/java_md_solinux.c | 7 ++ + 19 files changed, 298 insertions(+) + create mode 100644 hotspot/test/runtime/containers/docker/TestNUMANodes.java + +diff --git a/hotspot/make/aix/makefiles/mapfile-vers-debug b/hotspot/make/aix/makefiles/mapfile-vers-debug +index 760f955..127794c 100644 +--- a/hotspot/make/aix/makefiles/mapfile-vers-debug ++++ b/hotspot/make/aix/makefiles/mapfile-vers-debug +@@ -28,6 +28,7 @@ SUNWprivate_1.1 { + global: + # JNI + JNI_CreateJavaVM; ++ JNI_SetCParam; + JNI_GetCreatedJavaVMs; + JNI_GetDefaultJavaVMInitArgs; + +diff --git a/hotspot/make/aix/makefiles/mapfile-vers-product b/hotspot/make/aix/makefiles/mapfile-vers-product +index e84b671..2bbfb32 100644 +--- a/hotspot/make/aix/makefiles/mapfile-vers-product ++++ b/hotspot/make/aix/makefiles/mapfile-vers-product +@@ -28,6 +28,7 @@ SUNWprivate_1.1 { + global: + # JNI + JNI_CreateJavaVM; ++ JNI_SetCParam; + JNI_GetCreatedJavaVMs; + JNI_GetDefaultJavaVMInitArgs; + +diff --git a/hotspot/make/linux/makefiles/mapfile-vers-debug b/hotspot/make/linux/makefiles/mapfile-vers-debug +index 48b4f9d..1ebe436 100644 +--- a/hotspot/make/linux/makefiles/mapfile-vers-debug ++++ b/hotspot/make/linux/makefiles/mapfile-vers-debug +@@ -28,6 +28,7 @@ SUNWprivate_1.1 { + global: + # JNI + JNI_CreateJavaVM; ++ JNI_SetCParam; + JNI_GetCreatedJavaVMs; + JNI_GetDefaultJavaVMInitArgs; + +diff --git a/hotspot/make/linux/makefiles/mapfile-vers-product b/hotspot/make/linux/makefiles/mapfile-vers-product +index d4100d7..75e5278 100644 +--- a/hotspot/make/linux/makefiles/mapfile-vers-product ++++ b/hotspot/make/linux/makefiles/mapfile-vers-product +@@ -28,6 +28,7 @@ SUNWprivate_1.1 { + global: + # JNI + JNI_CreateJavaVM; ++ JNI_SetCParam; + JNI_GetCreatedJavaVMs; + JNI_GetDefaultJavaVMInitArgs; + +diff --git a/hotspot/make/solaris/makefiles/mapfile-vers b/hotspot/make/solaris/makefiles/mapfile-vers +index 26288b7..41045dd 100644 +--- a/hotspot/make/solaris/makefiles/mapfile-vers ++++ b/hotspot/make/solaris/makefiles/mapfile-vers +@@ -28,6 +28,7 @@ SUNWprivate_1.1 { + global: + # JNI + JNI_CreateJavaVM; ++ JNI_SetCParam; + JNI_GetCreatedJavaVMs; + JNI_GetDefaultJavaVMInitArgs; + +diff --git a/hotspot/make/windows/jvmexp.lcf b/hotspot/make/windows/jvmexp.lcf +index 6489d02..4bba798 100644 +--- a/hotspot/make/windows/jvmexp.lcf ++++ b/hotspot/make/windows/jvmexp.lcf +@@ -1,5 +1,6 @@ + -export:JNI_GetDefaultJavaVMInitArgs + -export:JNI_CreateJavaVM ++-export:JNI_SetCParam; + -export:JNI_GetCreatedJavaVMs + + -export:jio_snprintf +diff --git a/hotspot/make/windows/jvmexp_g.lcf b/hotspot/make/windows/jvmexp_g.lcf +index 6489d02..4bba798 100644 +--- a/hotspot/make/windows/jvmexp_g.lcf ++++ b/hotspot/make/windows/jvmexp_g.lcf +@@ -1,5 +1,6 @@ + -export:JNI_GetDefaultJavaVMInitArgs + -export:JNI_CreateJavaVM ++-export:JNI_SetCParam; + -export:JNI_GetCreatedJavaVMs + + -export:jio_snprintf +diff --git a/hotspot/make/windows/makefiles/vm.make b/hotspot/make/windows/makefiles/vm.make +index 5322a4b..fd5e5d2 100644 +--- a/hotspot/make/windows/makefiles/vm.make ++++ b/hotspot/make/windows/makefiles/vm.make +@@ -86,6 +86,7 @@ AGCT_EXPORT=/export:AsyncGetCallTrace + LD_FLAGS=$(LD_FLAGS) $(STACK_SIZE) /subsystem:windows /dll /base:0x8000000 \ + /export:JNI_GetDefaultJavaVMInitArgs \ + /export:JNI_CreateJavaVM \ ++ /export:JNI_SetCParam \ + /export:JVM_FindClassFromBootLoader \ + /export:JNI_GetCreatedJavaVMs \ + /export:jio_snprintf \ +diff --git a/hotspot/src/os/linux/vm/os_linux.cpp b/hotspot/src/os/linux/vm/os_linux.cpp +index 1ec68ab..ab28ee3 100644 +--- a/hotspot/src/os/linux/vm/os_linux.cpp ++++ b/hotspot/src/os/linux/vm/os_linux.cpp +@@ -133,6 +133,8 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC + #define LARGEPAGES_BIT (1 << 6) + //////////////////////////////////////////////////////////////////////////////// + // global variables ++extern char** argv_for_execvp; ++ + julong os::Linux::_physical_memory = 0; + + address os::Linux::_initial_thread_stack_bottom = NULL; +@@ -3129,6 +3131,77 @@ void* os::Linux::libnuma_v2_dlsym(void* handle, const char* name) { + return dlvsym(handle, name, "libnuma_1.2"); + } + ++void os::Linux::parse_numa_nodes() { ++ if (NUMANodes == NULL && NUMANodesRandom == 0) { ++ return; ++ } ++ const char* numa_nodes = NUMANodes; ++ // Max length for "%d-%d" is 24 ++ char buf[24] = {0}; ++ if (NUMANodesRandom != 0) { ++ int nodes_to_bind = NUMANodesRandom; ++ int nodes_num = Linux::numa_max_node() + 1; ++ const int MAX_NUMA = 1000000; ++ if (nodes_num > 0 && ++ nodes_num < MAX_NUMA && ++ nodes_to_bind > 0 && ++ nodes_to_bind < nodes_num) { ++ int bound = 1; ++ while (bound < nodes_to_bind) { ++ bound *= 2; ++ } ++ struct timeval tv; ++ gettimeofday(&tv,NULL); ++ srand(tv.tv_usec); ++ int first = 0; ++ if (nodes_num > bound) { ++ first = rand() % (nodes_num / bound) * bound; ++ } ++ if (bound != nodes_to_bind) { ++ first += rand() % (1 + bound - nodes_to_bind); ++ } ++ sprintf(buf, "%d-%d", first, first + nodes_to_bind - 1); ++ numa_nodes = buf; ++ if (LogNUMANodes) { ++ warning("NUMANodes is converted to %s, with total %d nodes!", buf, nodes_num); ++ } ++ } else { ++ if (LogNUMANodes) { ++ warning("The count of nodes to bind should be less that the count of all nodes, Skip!"); ++ } ++ return; ++ } ++ } ++ bitmask* mask = os::Linux::numa_parse_nodestring_all(numa_nodes); ++ if (!mask) { ++ if (LogNUMANodes) { ++ warning("<%s> is invalid", numa_nodes); ++ } ++ return; ++ } ++ if (os::Linux::numa_bitmask_equal(mask, os::Linux::_numa_membind_bitmask)) { ++ os::Linux::numa_bitmask_free(mask); ++ if (LogNUMANodes) { ++ warning("Mempolicy is not changed, param: %s", numa_nodes); ++ } ++ return; ++ } ++ errno = 0; ++ os::Linux::numa_run_on_node_mask(mask); ++ if (errno) { ++ perror("sched_setaffinity"); ++ } ++ errno = 0; ++ os::Linux::numa_set_membind(mask); ++ int errtmp = errno; ++ os::Linux::numa_bitmask_free(mask); ++ if (errtmp) { ++ perror("numa_set_membind"); ++ } else { ++ execvp(*argv_for_execvp, argv_for_execvp); ++ } ++} ++ + bool os::Linux::libnuma_init() { + // sched_getcpu() should be in libc. + set_sched_getcpu(CAST_TO_FN_PTR(sched_getcpu_func_t, +@@ -3169,6 +3242,16 @@ bool os::Linux::libnuma_init() { + libnuma_dlsym(handle, "numa_move_pages"))); + set_numa_run_on_node(CAST_TO_FN_PTR(numa_run_on_node_func_t, + libnuma_dlsym(handle, "numa_run_on_node"))); ++ set_numa_parse_nodestring_all(CAST_TO_FN_PTR(numa_parse_nodestring_all_func_t, ++ libnuma_dlsym(handle, "numa_parse_nodestring_all"))); ++ set_numa_run_on_node_mask(CAST_TO_FN_PTR(numa_run_on_node_mask_func_t, ++ libnuma_v2_dlsym(handle, "numa_run_on_node_mask"))); ++ set_numa_bitmask_equal(CAST_TO_FN_PTR(numa_bitmask_equal_func_t, ++ libnuma_v2_dlsym(handle, "numa_bitmask_equal"))); ++ set_numa_set_membind(CAST_TO_FN_PTR(numa_set_membind_func_t, ++ libnuma_v2_dlsym(handle, "numa_set_membind"))); ++ set_numa_bitmask_free(CAST_TO_FN_PTR(numa_bitmask_free_func_t, ++ libnuma_dlsym(handle, "numa_bitmask_free"))); + + if (numa_available() != -1) { + set_numa_all_nodes((unsigned long*)libnuma_dlsym(handle, "numa_all_nodes")); +@@ -3176,6 +3259,9 @@ bool os::Linux::libnuma_init() { + set_numa_nodes_ptr((struct bitmask **)libnuma_dlsym(handle, "numa_nodes_ptr")); + set_numa_interleave_bitmask(_numa_get_interleave_mask()); + set_numa_membind_bitmask(_numa_get_membind()); ++ if (isbound_to_all_node()) { ++ parse_numa_nodes(); ++ } + // Create an index -> node mapping, since nodes are not always consecutive + _nindex_to_node = new (ResourceObj::C_HEAP, mtInternal) GrowableArray(0, true); + rebuild_nindex_to_node_map(); +@@ -3295,6 +3381,11 @@ os::Linux::numa_get_membind_func_t os::Linux::_numa_get_membind; + os::Linux::numa_get_interleave_mask_func_t os::Linux::_numa_get_interleave_mask; + os::Linux::numa_move_pages_func_t os::Linux::_numa_move_pages; + os::Linux::numa_run_on_node_func_t os::Linux::_numa_run_on_node; ++os::Linux::numa_parse_nodestring_all_func_t os::Linux::_numa_parse_nodestring_all; ++os::Linux::numa_run_on_node_mask_func_t os::Linux::_numa_run_on_node_mask; ++os::Linux::numa_bitmask_equal_func_t os::Linux::_numa_bitmask_equal; ++os::Linux::numa_set_membind_func_t os::Linux::_numa_set_membind; ++os::Linux::numa_bitmask_free_func_t os::Linux::_numa_bitmask_free; + os::Linux::NumaAllocationPolicy os::Linux::_current_numa_policy; + unsigned long* os::Linux::_numa_all_nodes; + struct bitmask* os::Linux::_numa_all_nodes_ptr; +diff --git a/hotspot/src/os/linux/vm/os_linux.hpp b/hotspot/src/os/linux/vm/os_linux.hpp +index 4ee2c9b..18ac68f 100644 +--- a/hotspot/src/os/linux/vm/os_linux.hpp ++++ b/hotspot/src/os/linux/vm/os_linux.hpp +@@ -195,6 +195,7 @@ class Linux { + static bool is_floating_stack() { return _is_floating_stack; } + + static void libpthread_init(); ++ static void parse_numa_nodes(); + static bool libnuma_init(); + static void* libnuma_dlsym(void* handle, const char* name); + // libnuma v2 (libnuma_1.2) symbols +@@ -283,6 +284,11 @@ private: + typedef struct bitmask* (*numa_get_interleave_mask_func_t)(void); + typedef long (*numa_move_pages_func_t)(int pid, unsigned long count, void **pages, const int *nodes, int *status, int flags); + typedef int (*numa_run_on_node_func_t)(int node); ++ typedef struct bitmask* (*numa_parse_nodestring_all_func_t)(const char*); ++ typedef int (*numa_run_on_node_mask_func_t)(struct bitmask* mask); ++ typedef void (*numa_set_membind_func_t)(struct bitmask* mask); ++ typedef int (*numa_bitmask_equal_func_t)(struct bitmask* mask, struct bitmask* mask1); ++ typedef void (*numa_bitmask_free_func_t)(struct bitmask* mask); + + typedef void (*numa_set_bind_policy_func_t)(int policy); + typedef int (*numa_bitmask_isbitset_func_t)(struct bitmask *bmp, unsigned int n); +@@ -303,6 +309,11 @@ private: + static numa_get_interleave_mask_func_t _numa_get_interleave_mask; + static numa_move_pages_func_t _numa_move_pages; + static numa_run_on_node_func_t _numa_run_on_node; ++ static numa_parse_nodestring_all_func_t _numa_parse_nodestring_all; ++ static numa_run_on_node_mask_func_t _numa_run_on_node_mask; ++ static numa_bitmask_equal_func_t _numa_bitmask_equal; ++ static numa_set_membind_func_t _numa_set_membind; ++ static numa_bitmask_free_func_t _numa_bitmask_free; + + static unsigned long* _numa_all_nodes; + static struct bitmask* _numa_all_nodes_ptr; +@@ -325,6 +336,11 @@ private: + static void set_numa_get_interleave_mask(numa_get_interleave_mask_func_t func) { _numa_get_interleave_mask = func; } + static void set_numa_move_pages(numa_move_pages_func_t func) { _numa_move_pages = func; } + static void set_numa_run_on_node(numa_run_on_node_func_t func) { _numa_run_on_node = func; } ++ static void set_numa_parse_nodestring_all(numa_parse_nodestring_all_func_t func) { _numa_parse_nodestring_all = func; } ++ static void set_numa_run_on_node_mask(numa_run_on_node_mask_func_t func) { _numa_run_on_node_mask = func; } ++ static void set_numa_bitmask_equal(numa_bitmask_equal_func_t func) { _numa_bitmask_equal = func; } ++ static void set_numa_set_membind(numa_set_membind_func_t func) { _numa_set_membind = func; } ++ static void set_numa_bitmask_free(numa_bitmask_free_func_t func) { _numa_bitmask_free = func; } + static void set_numa_all_nodes(unsigned long* ptr) { _numa_all_nodes = ptr; } + static void set_numa_all_nodes_ptr(struct bitmask **ptr) { _numa_all_nodes_ptr = (ptr == NULL ? NULL : *ptr); } + static void set_numa_nodes_ptr(struct bitmask **ptr) { _numa_nodes_ptr = (ptr == NULL ? NULL : *ptr); } +@@ -472,6 +488,41 @@ public: + static mallinfo_retval_t get_mallinfo(glibc_mallinfo2* out); + #endif + ++ static bool isbound_to_all_node() { ++ if (_numa_membind_bitmask != NULL && _numa_max_node != NULL && _numa_bitmask_isbitset != NULL) { ++ unsigned int highest_node_number = _numa_max_node(); ++ for (unsigned int node = 0; node <= highest_node_number; node++) { ++ if (!_numa_bitmask_isbitset(_numa_membind_bitmask, node)) { ++ return false; ++ } ++ } ++ } ++ return true; ++ } ++ ++ static bitmask* numa_parse_nodestring_all(const char* s) { ++ return _numa_parse_nodestring_all != NULL ? _numa_parse_nodestring_all(s) : NULL; ++ } ++ ++ static int numa_run_on_node_mask(bitmask* bitmask) { ++ return _numa_run_on_node_mask != NULL ? _numa_run_on_node_mask(bitmask) : -1; ++ } ++ ++ static int numa_bitmask_equal(bitmask* bitmask, struct bitmask* bitmask1) { ++ return _numa_bitmask_equal != NULL ? _numa_bitmask_equal(bitmask, bitmask1) : 1; ++ } ++ ++ static void numa_set_membind(bitmask* bitmask) { ++ if (_numa_set_membind != NULL) { ++ _numa_set_membind(bitmask); ++ } ++ } ++ ++ static void numa_bitmask_free(bitmask* bitmask) { ++ if (_numa_bitmask_free != NULL) { ++ _numa_bitmask_free(bitmask); ++ } ++ } + }; + + +diff --git a/hotspot/src/share/vm/prims/jni.cpp b/hotspot/src/share/vm/prims/jni.cpp +index dde3975..dd40c2c 100644 +--- a/hotspot/src/share/vm/prims/jni.cpp ++++ b/hotspot/src/share/vm/prims/jni.cpp +@@ -5188,6 +5188,12 @@ DT_RETURN_MARK_DECL(CreateJavaVM, jint + , HOTSPOT_JNI_CREATEJAVAVM_RETURN(_ret_ref)); + #endif /* USDT2 */ + ++const char** argv_for_execvp; ++ ++_JNI_IMPORT_OR_EXPORT_ void JNICALL JNI_SetCParam(char** raw_argv) { ++ argv_for_execvp = (const char**)raw_argv; ++} ++ + _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) { + #ifndef USDT2 + HS_DTRACE_PROBE3(hotspot_jni, CreateJavaVM__entry, vm, penv, args); +diff --git a/hotspot/src/share/vm/prims/jni.h b/hotspot/src/share/vm/prims/jni.h +index 582f2c9..1c910e8 100644 +--- a/hotspot/src/share/vm/prims/jni.h ++++ b/hotspot/src/share/vm/prims/jni.h +@@ -1937,6 +1937,9 @@ JNI_GetDefaultJavaVMInitArgs(void *args); + _JNI_IMPORT_OR_EXPORT_ jint JNICALL + JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args); + ++_JNI_IMPORT_OR_EXPORT_ void JNICALL ++JNI_SetCParam(char**raw_argv); ++ + _JNI_IMPORT_OR_EXPORT_ jint JNICALL + JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); + +diff --git a/hotspot/src/share/vm/runtime/globals.hpp b/hotspot/src/share/vm/runtime/globals.hpp +index 2631971..3dd4c51 100644 +--- a/hotspot/src/share/vm/runtime/globals.hpp ++++ b/hotspot/src/share/vm/runtime/globals.hpp +@@ -613,6 +613,19 @@ class CommandLineFlags { + product(uintx, NUMAPageScanRate, 256, \ + "Maximum number of pages to include in the page scan procedure") \ + \ ++ product(bool, LogNUMANodes, false, \ ++ "Print NUMANodes") \ ++ \ ++ product(ccstr, NUMANodes, NULL, \ ++ "This parameter provides the same functionality as" \ ++ "'numactl --all -N -m '." \ ++ " can be '0-2', '0,1,2', 'all' and so on.") \ ++ \ ++ product(uintx, NUMANodesRandom, 0, \ ++ "Number of continuous nodes to bind" \ ++ "with the first node randomly chosen." \ ++ "NUMANodesRandom has higher priority than NUMANodes") \ ++ \ + product_pd(bool, NeedsDeoptSuspend, \ + "True for register window machines (sparc/ia64)") \ + \ +diff --git a/hotspot/test/runtime/containers/docker/CPUSetsReader.java b/hotspot/test/runtime/containers/docker/CPUSetsReader.java +index f6fa93e..cb8ced2 100644 +--- a/hotspot/test/runtime/containers/docker/CPUSetsReader.java ++++ b/hotspot/test/runtime/containers/docker/CPUSetsReader.java +@@ -51,6 +51,15 @@ public class CPUSetsReader { + Asserts.assertEquals(listToString(parseCpuSet(cpuSet)), expectedResult); + } + ++ public static int getNumCpus() { ++ String path = "/proc/cpuinfo"; ++ try { ++ Stream stream = Files.lines(Paths.get(path)); ++ return (int) stream.filter(line -> line.startsWith("processor")).count(); ++ } catch (IOException e) { ++ return 0; ++ } ++ } + + public static String readFromProcStatus(String setType) { + String path = PROC_SELF_STATUS_PATH; +diff --git a/hotspot/test/runtime/containers/docker/TestNUMANodes.java b/hotspot/test/runtime/containers/docker/TestNUMANodes.java +new file mode 100644 +index 0000000..b781484 +--- /dev/null ++++ b/hotspot/test/runtime/containers/docker/TestNUMANodes.java +@@ -0,0 +1,102 @@ ++/** ++ * @test TestNUMANodes.java ++ * @library /testlibrary ++ * @build CPUSetsReader TestNUMANodes ++ * @run main/othervm TestNUMANodes 1 -XX:+UseNUMA -XX:NUMANodes=0 -XX:-LogNUMANodes ++ * @run main/othervm TestNUMANodes 2 -XX:+UseNUMA -XX:NUMANodes=all -XX:+LogNUMANodes ++ * @run main/othervm TestNUMANodes 3 -XX:+UseNUMA -XX:NUMANodesRandom=1 -XX:+LogNUMANodes ++ * @run main/othervm TestNUMANodes 4 -XX:+UseNUMA -XX:NUMANodesRandom=4 -XX:+LogNUMANodes ++ * @run main/othervm TestNUMANodes 5 -XX:+UseNUMA -XX:NUMANodes=100-200 -XX:+LogNUMANodes ++ * @summary test numanodes ++ * @author zhoulei ++ */ ++ ++import java.io.IOException; ++import java.nio.file.Files; ++import java.nio.file.Paths; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.List; ++import java.util.Optional; ++import java.util.stream.Collectors; ++import java.util.stream.IntStream; ++import java.util.stream.Stream; ++import com.oracle.java.testlibrary.Asserts; ++import com.oracle.java.testlibrary.OutputAnalyzer; ++import com.oracle.java.testlibrary.ProcessTools; ++ ++public class TestNUMANodes { ++ ++ private static int getNUMAs() throws Exception { ++ final String[] arguments = {"numactl", "-H"}; ++ OutputAnalyzer output = ProcessTools.executeProcess(new ProcessBuilder(arguments)); ++ String[] numainfo = output.getStdout().split("\n"); ++ Optional o = Arrays.asList(numainfo).stream() ++ .filter(line -> line.contains("available")) ++ .findFirst(); ++ String numas = o.get(); ++ return Integer.valueOf(numas.substring(11, 12)); ++ } ++ ++ private static class ExeTest { ++ public static void main(String[] str) throws Exception { ++ int numCpus = CPUSetsReader.getNumCpus(); ++ String cpuSetStr = CPUSetsReader.readFromProcStatus("Cpus_allowed_list"); ++ String[] cpus = cpuSetStr.split(","); ++ int total = 0; ++ for (String cpu : cpus) { ++ String[] c = cpu.split("-"); ++ int start = Integer.valueOf(c[0]); ++ int end = Integer.valueOf(c[1]); ++ total += end - start + 1; ++ } ++ System.err.print(total); ++ } ++ } ++ ++ private static OutputAnalyzer forkProcess(String[] args) throws Exception { ++ final String[] arguments = { ++ args[1], ++ args[2], ++ args[3], ++ ExeTest.class.getName(), ++ args[0] ++ }; ++ ++ ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(arguments); ++ OutputAnalyzer output = new OutputAnalyzer(pb.start()); ++ output.shouldHaveExitValue(0); ++ return output; ++ } ++ ++ public static void main(String[] args)throws Exception { ++ OutputAnalyzer output = forkProcess(args); ++ String err = output.getStderr(); ++ String out = output.getStdout(); ++ int c = Integer.parseInt(args[0]); ++ int numas = TestNUMANodes.getNUMAs(); ++ int numCpus = CPUSetsReader.getNumCpus(); ++ switch(c) { ++ case 1: ++ int cpuUsed = Integer.valueOf(err); ++ Asserts.assertTrue(cpuUsed * numas == numCpus); ++ break; ++ case 2: ++ Asserts.assertTrue(err.contains("Mempolicy is not changed")); ++ break; ++ case 3: ++ if (numas > 1) { ++ Asserts.assertTrue(err.contains("NUMANodes is converted to")); ++ } ++ break; ++ case 4: ++ Asserts.assertTrue(err.contains("The count of nodes to bind should be")); ++ break; ++ case 5: ++ Asserts.assertTrue(err.contains("is invalid")); ++ break; ++ default: ++ break; ++ } ++ } ++} +diff --git a/jdk/src/share/bin/java.c b/jdk/src/share/bin/java.c +index d74b185..c3d3b1b 100644 +--- a/jdk/src/share/bin/java.c ++++ b/jdk/src/share/bin/java.c +@@ -245,6 +245,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ + + ifn.CreateJavaVM = 0; + ifn.GetDefaultJavaVMInitArgs = 0; ++ ifn.raw_argv = argv; + + if (JLI_IsTraceLauncher()) { + start = CounterGet(); +@@ -1237,6 +1238,7 @@ InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn) + i, args.options[i].optionString); + } + ++ ifn->SetCParam(ifn->raw_argv); + r = ifn->CreateJavaVM(pvm, (void **)penv, &args); + JLI_MemFree(options); + return r == JNI_OK; +diff --git a/jdk/src/share/bin/java.h b/jdk/src/share/bin/java.h +index 9dc0e16..9a8b839 100644 +--- a/jdk/src/share/bin/java.h ++++ b/jdk/src/share/bin/java.h +@@ -78,13 +78,16 @@ + * Pointers to the needed JNI invocation API, initialized by LoadJavaVM. + */ + typedef jint (JNICALL *CreateJavaVM_t)(JavaVM **pvm, void **env, void *args); ++typedef void (JNICALL *SetCParam_t)(char** raw_argv); + typedef jint (JNICALL *GetDefaultJavaVMInitArgs_t)(void *args); + typedef jint (JNICALL *GetCreatedJavaVMs_t)(JavaVM **vmBuf, jsize bufLen, jsize *nVMs); + + typedef struct { + CreateJavaVM_t CreateJavaVM; ++ SetCParam_t SetCParam; + GetDefaultJavaVMInitArgs_t GetDefaultJavaVMInitArgs; + GetCreatedJavaVMs_t GetCreatedJavaVMs; ++ char** raw_argv; + } InvocationFunctions; + + int +diff --git a/jdk/src/share/javavm/export/jni.h b/jdk/src/share/javavm/export/jni.h +index 2e83cb7..8567766 100644 +--- a/jdk/src/share/javavm/export/jni.h ++++ b/jdk/src/share/javavm/export/jni.h +@@ -1937,6 +1937,9 @@ JNI_GetDefaultJavaVMInitArgs(void *args); + _JNI_IMPORT_OR_EXPORT_ jint JNICALL + JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args); + ++_JNI_IMPORT_OR_EXPORT_ void JNICALL ++JNI_SetCParam(char** raw_argv); ++ + _JNI_IMPORT_OR_EXPORT_ jint JNICALL + JNI_GetCreatedJavaVMs(JavaVM **, jsize, jsize *); + +diff --git a/jdk/src/solaris/bin/java_md_solinux.c b/jdk/src/solaris/bin/java_md_solinux.c +index a967137..9865f9d 100644 +--- a/jdk/src/solaris/bin/java_md_solinux.c ++++ b/jdk/src/solaris/bin/java_md_solinux.c +@@ -903,6 +903,13 @@ LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn) + return JNI_FALSE; + } + ++ ifn->SetCParam = (SetCParam_t) ++ dlsym(libjvm, "JNI_SetCParam"); ++ if (ifn->SetCParam == NULL) { ++ JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror()); ++ return JNI_FALSE; ++ } ++ + ifn->GetDefaultJavaVMInitArgs = (GetDefaultJavaVMInitArgs_t) + dlsym(libjvm, "JNI_GetDefaultJavaVMInitArgs"); + if (ifn->GetDefaultJavaVMInitArgs == NULL) { +-- +1.8.3.1