Path: blob/master/src/hotspot/share/runtime/java.cpp
40951 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "jvm.h"26#include "cds/dynamicArchive.hpp"27#include "classfile/classLoaderDataGraph.hpp"28#include "classfile/javaClasses.hpp"29#include "classfile/stringTable.hpp"30#include "classfile/symbolTable.hpp"31#include "classfile/systemDictionary.hpp"32#include "code/codeCache.hpp"33#include "compiler/compileBroker.hpp"34#include "compiler/compilerOracle.hpp"35#include "gc/shared/collectedHeap.hpp"36#include "gc/shared/stringdedup/stringDedup.hpp"37#include "interpreter/bytecodeHistogram.hpp"38#include "jfr/jfrEvents.hpp"39#include "jfr/support/jfrThreadId.hpp"40#if INCLUDE_JVMCI41#include "jvmci/jvmci.hpp"42#endif43#include "logging/log.hpp"44#include "logging/logStream.hpp"45#include "memory/metaspaceUtils.hpp"46#include "memory/oopFactory.hpp"47#include "memory/resourceArea.hpp"48#include "memory/universe.hpp"49#include "oops/constantPool.hpp"50#include "oops/generateOopMap.hpp"51#include "oops/instanceKlass.hpp"52#include "oops/instanceOop.hpp"53#include "oops/klassVtable.hpp"54#include "oops/method.hpp"55#include "oops/objArrayOop.hpp"56#include "oops/oop.inline.hpp"57#include "oops/symbol.hpp"58#include "prims/jvmtiExport.hpp"59#include "runtime/biasedLocking.hpp"60#include "runtime/deoptimization.hpp"61#include "runtime/flags/flagSetting.hpp"62#include "runtime/handles.inline.hpp"63#include "runtime/init.hpp"64#include "runtime/interfaceSupport.inline.hpp"65#include "runtime/java.hpp"66#include "runtime/sharedRuntime.hpp"67#include "runtime/statSampler.hpp"68#include "runtime/stubRoutines.hpp"69#include "runtime/sweeper.hpp"70#include "runtime/task.hpp"71#include "runtime/thread.inline.hpp"72#include "runtime/timer.hpp"73#include "runtime/vmOperations.hpp"74#include "runtime/vmThread.hpp"75#include "runtime/vm_version.hpp"76#include "services/memTracker.hpp"77#include "utilities/dtrace.hpp"78#include "utilities/globalDefinitions.hpp"79#include "utilities/macros.hpp"80#include "utilities/vmError.hpp"81#ifdef COMPILER182#include "c1/c1_Compiler.hpp"83#include "c1/c1_Runtime1.hpp"84#endif85#ifdef COMPILER286#include "code/compiledIC.hpp"87#include "opto/compile.hpp"88#include "opto/indexSet.hpp"89#include "opto/runtime.hpp"90#endif91#if INCLUDE_JFR92#include "jfr/jfr.hpp"93#endif9495GrowableArray<Method*>* collected_profiled_methods;9697int compare_methods(Method** a, Method** b) {98// compiled_invocation_count() returns int64_t, forcing the entire expression99// to be evaluated as int64_t. Overflow is not an issue.100int64_t diff = (((*b)->invocation_count() + (*b)->compiled_invocation_count())101- ((*a)->invocation_count() + (*a)->compiled_invocation_count()));102return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;103}104105void collect_profiled_methods(Method* m) {106Thread* thread = Thread::current();107methodHandle mh(thread, m);108if ((m->method_data() != NULL) &&109(PrintMethodData || CompilerOracle::should_print(mh))) {110collected_profiled_methods->push(m);111}112}113114void print_method_profiling_data() {115if (ProfileInterpreter COMPILER1_PRESENT(|| C1UpdateMethodData) &&116(PrintMethodData || CompilerOracle::should_print_methods())) {117ResourceMark rm;118collected_profiled_methods = new GrowableArray<Method*>(1024);119SystemDictionary::methods_do(collect_profiled_methods);120collected_profiled_methods->sort(&compare_methods);121122int count = collected_profiled_methods->length();123int total_size = 0;124if (count > 0) {125for (int index = 0; index < count; index++) {126Method* m = collected_profiled_methods->at(index);127ttyLocker ttyl;128tty->print_cr("------------------------------------------------------------------------");129m->print_invocation_count();130tty->print_cr(" mdo size: %d bytes", m->method_data()->size_in_bytes());131tty->cr();132// Dump data on parameters if any133if (m->method_data() != NULL && m->method_data()->parameters_type_data() != NULL) {134tty->fill_to(2);135m->method_data()->parameters_type_data()->print_data_on(tty);136}137m->print_codes();138total_size += m->method_data()->size_in_bytes();139}140tty->print_cr("------------------------------------------------------------------------");141tty->print_cr("Total MDO size: %d bytes", total_size);142}143}144}145146147#ifndef PRODUCT148149// Statistics printing (method invocation histogram)150151GrowableArray<Method*>* collected_invoked_methods;152153void collect_invoked_methods(Method* m) {154if (m->invocation_count() + m->compiled_invocation_count() >= 1) {155collected_invoked_methods->push(m);156}157}158159160// Invocation count accumulators should be unsigned long to shift the161// overflow border. Longer-running workloads tend to create invocation162// counts which already overflow 32-bit counters for individual methods.163void print_method_invocation_histogram() {164ResourceMark rm;165collected_invoked_methods = new GrowableArray<Method*>(1024);166SystemDictionary::methods_do(collect_invoked_methods);167collected_invoked_methods->sort(&compare_methods);168//169tty->cr();170tty->print_cr("Histogram Over Method Invocation Counters (cutoff = " INTX_FORMAT "):", MethodHistogramCutoff);171tty->cr();172tty->print_cr("____Count_(I+C)____Method________________________Module_________________");173uint64_t total = 0,174int_total = 0,175comp_total = 0,176special_total= 0,177static_total = 0,178final_total = 0,179synch_total = 0,180native_total = 0,181access_total = 0;182for (int index = 0; index < collected_invoked_methods->length(); index++) {183// Counter values returned from getter methods are signed int.184// To shift the overflow border by a factor of two, we interpret185// them here as unsigned long. A counter can't be negative anyway.186Method* m = collected_invoked_methods->at(index);187uint64_t iic = (uint64_t)m->invocation_count();188uint64_t cic = (uint64_t)m->compiled_invocation_count();189if ((iic + cic) >= (uint64_t)MethodHistogramCutoff) m->print_invocation_count();190int_total += iic;191comp_total += cic;192if (m->is_final()) final_total += iic + cic;193if (m->is_static()) static_total += iic + cic;194if (m->is_synchronized()) synch_total += iic + cic;195if (m->is_native()) native_total += iic + cic;196if (m->is_accessor()) access_total += iic + cic;197}198tty->cr();199total = int_total + comp_total;200special_total = final_total + static_total +synch_total + native_total + access_total;201tty->print_cr("Invocations summary for %d methods:", collected_invoked_methods->length());202tty->print_cr("\t" UINT64_FORMAT_W(12) " (100%%) total", total);203tty->print_cr("\t" UINT64_FORMAT_W(12) " (%4.1f%%) |- interpreted", int_total, 100.0 * int_total / total);204tty->print_cr("\t" UINT64_FORMAT_W(12) " (%4.1f%%) |- compiled", comp_total, 100.0 * comp_total / total);205tty->print_cr("\t" UINT64_FORMAT_W(12) " (%4.1f%%) |- special methods (interpreted and compiled)",206special_total, 100.0 * special_total/ total);207tty->print_cr("\t" UINT64_FORMAT_W(12) " (%4.1f%%) |- synchronized",synch_total, 100.0 * synch_total / total);208tty->print_cr("\t" UINT64_FORMAT_W(12) " (%4.1f%%) |- final", final_total, 100.0 * final_total / total);209tty->print_cr("\t" UINT64_FORMAT_W(12) " (%4.1f%%) |- static", static_total, 100.0 * static_total / total);210tty->print_cr("\t" UINT64_FORMAT_W(12) " (%4.1f%%) |- native", native_total, 100.0 * native_total / total);211tty->print_cr("\t" UINT64_FORMAT_W(12) " (%4.1f%%) |- accessor", access_total, 100.0 * access_total / total);212tty->cr();213SharedRuntime::print_call_statistics(comp_total);214}215216void print_bytecode_count() {217if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {218tty->print_cr("[BytecodeCounter::counter_value = %d]", BytecodeCounter::counter_value());219}220}221222223// General statistics printing (profiling ...)224void print_statistics() {225if (CITime) {226CompileBroker::print_times();227}228229#ifdef COMPILER1230if ((PrintC1Statistics || LogVMOutput || LogCompilation) && UseCompiler) {231FlagSetting fs(DisplayVMOutput, DisplayVMOutput && PrintC1Statistics);232Runtime1::print_statistics();233Deoptimization::print_statistics();234SharedRuntime::print_statistics();235}236#endif /* COMPILER1 */237238#ifdef COMPILER2239if ((PrintOptoStatistics || LogVMOutput || LogCompilation) && UseCompiler) {240FlagSetting fs(DisplayVMOutput, DisplayVMOutput && PrintOptoStatistics);241Compile::print_statistics();242#ifndef COMPILER1243Deoptimization::print_statistics();244SharedRuntime::print_statistics();245#endif //COMPILER1246os::print_statistics();247}248249if (PrintLockStatistics || PrintPreciseBiasedLockingStatistics || PrintPreciseRTMLockingStatistics) {250OptoRuntime::print_named_counters();251}252#ifdef ASSERT253if (CollectIndexSetStatistics) {254IndexSet::print_statistics();255}256#endif // ASSERT257#else // COMPILER2258#if INCLUDE_JVMCI259#ifndef COMPILER1260if ((TraceDeoptimization || LogVMOutput || LogCompilation) && UseCompiler) {261FlagSetting fs(DisplayVMOutput, DisplayVMOutput && TraceDeoptimization);262Deoptimization::print_statistics();263SharedRuntime::print_statistics();264}265#endif // COMPILER1266#endif // INCLUDE_JVMCI267#endif // COMPILER2268269if (PrintNMethodStatistics) {270nmethod::print_statistics();271}272if (CountCompiledCalls) {273print_method_invocation_histogram();274}275276print_method_profiling_data();277278if (TimeOopMap) {279GenerateOopMap::print_time();280}281if (PrintSymbolTableSizeHistogram) {282SymbolTable::print_histogram();283}284if (CountBytecodes || TraceBytecodes || StopInterpreterAt) {285BytecodeCounter::print();286}287if (PrintBytecodePairHistogram) {288BytecodePairHistogram::print();289}290291if (PrintCodeCache) {292MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);293CodeCache::print();294}295296// CodeHeap State Analytics.297// Does also call NMethodSweeper::print(tty)298if (PrintCodeHeapAnalytics) {299CompileBroker::print_heapinfo(NULL, "all", 4096); // details300} else if (PrintMethodFlushingStatistics) {301NMethodSweeper::print(tty);302}303304if (PrintCodeCache2) {305MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);306CodeCache::print_internals();307}308309if (PrintVtableStats) {310klassVtable::print_statistics();311klassItable::print_statistics();312}313if (VerifyOops && Verbose) {314tty->print_cr("+VerifyOops count: %d", StubRoutines::verify_oop_count());315}316317print_bytecode_count();318319if (PrintSystemDictionaryAtExit) {320ResourceMark rm;321MutexLocker mcld(ClassLoaderDataGraph_lock);322SystemDictionary::print();323}324325if (PrintClassLoaderDataGraphAtExit) {326ResourceMark rm;327MutexLocker mcld(ClassLoaderDataGraph_lock);328ClassLoaderDataGraph::print();329}330331if (LogTouchedMethods && PrintTouchedMethodsAtExit) {332Method::print_touched_methods(tty);333}334335if (PrintBiasedLockingStatistics) {336BiasedLocking::print_counters();337}338339// Native memory tracking data340if (PrintNMTStatistics) {341MemTracker::final_report(tty);342}343344if (PrintMetaspaceStatisticsAtExit) {345MetaspaceUtils::print_basic_report(tty, 0);346}347348ThreadsSMRSupport::log_statistics();349}350351#else // PRODUCT MODE STATISTICS352353void print_statistics() {354355if (PrintMethodData) {356print_method_profiling_data();357}358359if (CITime) {360CompileBroker::print_times();361}362363if (PrintCodeCache) {364MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);365CodeCache::print();366}367368// CodeHeap State Analytics.369// Does also call NMethodSweeper::print(tty)370if (PrintCodeHeapAnalytics) {371CompileBroker::print_heapinfo(NULL, "all", 4096); // details372} else if (PrintMethodFlushingStatistics) {373NMethodSweeper::print(tty);374}375376#ifdef COMPILER2377if (PrintPreciseBiasedLockingStatistics || PrintPreciseRTMLockingStatistics) {378OptoRuntime::print_named_counters();379}380#endif381if (PrintBiasedLockingStatistics) {382BiasedLocking::print_counters();383}384385// Native memory tracking data386if (PrintNMTStatistics) {387MemTracker::final_report(tty);388}389390if (PrintMetaspaceStatisticsAtExit) {391MetaspaceUtils::print_basic_report(tty, 0);392}393394if (LogTouchedMethods && PrintTouchedMethodsAtExit) {395Method::print_touched_methods(tty);396}397398ThreadsSMRSupport::log_statistics();399}400401#endif402403// Note: before_exit() can be executed only once, if more than one threads404// are trying to shutdown the VM at the same time, only one thread405// can run before_exit() and all other threads must wait.406void before_exit(JavaThread* thread) {407#define BEFORE_EXIT_NOT_RUN 0408#define BEFORE_EXIT_RUNNING 1409#define BEFORE_EXIT_DONE 2410static jint volatile _before_exit_status = BEFORE_EXIT_NOT_RUN;411412// Note: don't use a Mutex to guard the entire before_exit(), as413// JVMTI post_thread_end_event and post_vm_death_event will run native code.414// A CAS or OSMutex would work just fine but then we need to manipulate415// thread state for Safepoint. Here we use Monitor wait() and notify_all()416// for synchronization.417{ MonitorLocker ml(BeforeExit_lock);418switch (_before_exit_status) {419case BEFORE_EXIT_NOT_RUN:420_before_exit_status = BEFORE_EXIT_RUNNING;421break;422case BEFORE_EXIT_RUNNING:423while (_before_exit_status == BEFORE_EXIT_RUNNING) {424ml.wait();425}426assert(_before_exit_status == BEFORE_EXIT_DONE, "invalid state");427return;428case BEFORE_EXIT_DONE:429// need block to avoid SS compiler bug430{431return;432}433}434}435436#if INCLUDE_JVMCI437if (EnableJVMCI) {438JVMCI::shutdown();439}440#endif441442// Hang forever on exit if we're reporting an error.443if (ShowMessageBoxOnError && VMError::is_error_reported()) {444os::infinite_sleep();445}446447EventThreadEnd event;448if (event.should_commit()) {449event.set_thread(JFR_THREAD_ID(thread));450event.commit();451}452453JFR_ONLY(Jfr::on_vm_shutdown();)454455// Stop the WatcherThread. We do this before disenrolling various456// PeriodicTasks to reduce the likelihood of races.457if (PeriodicTask::num_tasks() > 0) {458WatcherThread::stop();459}460461// shut down the StatSampler task462StatSampler::disengage();463StatSampler::destroy();464465// Shut down string deduplication if running.466if (StringDedup::is_enabled()) {467StringDedup::stop();468}469470// Stop concurrent GC threads471Universe::heap()->stop();472473// Print GC/heap related information.474Log(gc, heap, exit) log;475if (log.is_info()) {476ResourceMark rm;477LogStream ls_info(log.info());478Universe::print_on(&ls_info);479if (log.is_trace()) {480LogStream ls_trace(log.trace());481MutexLocker mcld(ClassLoaderDataGraph_lock);482ClassLoaderDataGraph::print_on(&ls_trace);483}484}485486if (PrintBytecodeHistogram) {487BytecodeHistogram::print();488}489490#ifdef LINUX491if (DumpPerfMapAtExit) {492CodeCache::write_perf_map();493}494#endif495496if (JvmtiExport::should_post_thread_life()) {497JvmtiExport::post_thread_end(thread);498}499500// Always call even when there are not JVMTI environments yet, since environments501// may be attached late and JVMTI must track phases of VM execution502JvmtiExport::post_vm_death();503Threads::shutdown_vm_agents();504505// Terminate the signal thread506// Note: we don't wait until it actually dies.507os::terminate_signal_thread();508509#if INCLUDE_CDS510if (DynamicDumpSharedSpaces) {511ExceptionMark em(thread);512DynamicArchive::dump();513if (thread->has_pending_exception()) {514ResourceMark rm(thread);515oop pending_exception = thread->pending_exception();516log_error(cds)("ArchiveClassesAtExit has failed %s: %s", pending_exception->klass()->external_name(),517java_lang_String::as_utf8_string(java_lang_Throwable::message(pending_exception)));518thread->clear_pending_exception();519}520}521#endif522523print_statistics();524Universe::heap()->print_tracing_info();525526{ MutexLocker ml(BeforeExit_lock);527_before_exit_status = BEFORE_EXIT_DONE;528BeforeExit_lock->notify_all();529}530531if (VerifyStringTableAtExit) {532size_t fail_cnt = StringTable::verify_and_compare_entries();533if (fail_cnt != 0) {534tty->print_cr("ERROR: fail_cnt=" SIZE_FORMAT, fail_cnt);535guarantee(fail_cnt == 0, "unexpected StringTable verification failures");536}537}538539#undef BEFORE_EXIT_NOT_RUN540#undef BEFORE_EXIT_RUNNING541#undef BEFORE_EXIT_DONE542}543544void vm_exit(int code) {545Thread* thread =546ThreadLocalStorage::is_initialized() ? Thread::current_or_null() : NULL;547if (thread == NULL) {548// very early initialization failure -- just exit549vm_direct_exit(code);550}551552// We'd like to add an entry to the XML log to show that the VM is553// terminating, but we can't safely do that here. The logic to make554// XML termination logging safe is tied to the termination of the555// VMThread, and it doesn't terminate on this exit path. See 8222534.556557if (VMThread::vm_thread() != NULL) {558if (thread->is_Java_thread()) {559// We must be "in_vm" for the code below to work correctly.560// Historically there must have been some exit path for which561// that was not the case and so we set it explicitly - even562// though we no longer know what that path may be.563thread->as_Java_thread()->set_thread_state(_thread_in_vm);564}565566// Fire off a VM_Exit operation to bring VM to a safepoint and exit567VM_Exit op(code);568569// 4945125 The vm thread comes to a safepoint during exit.570// GC vm_operations can get caught at the safepoint, and the571// heap is unparseable if they are caught. Grab the Heap_lock572// to prevent this. The GC vm_operations will not be able to573// queue until after we release it, but we never do that as we574// are terminating the VM process.575MutexLocker ml(Heap_lock);576577VMThread::execute(&op);578// should never reach here; but in case something wrong with VM Thread.579vm_direct_exit(code);580} else {581// VM thread is gone, just exit582vm_direct_exit(code);583}584ShouldNotReachHere();585}586587void notify_vm_shutdown() {588// For now, just a dtrace probe.589HOTSPOT_VM_SHUTDOWN();590}591592void vm_direct_exit(int code) {593notify_vm_shutdown();594os::wait_for_keypress_at_exit();595os::exit(code);596}597598void vm_direct_exit(int code, const char* message) {599if (message != nullptr) {600tty->print_cr("%s", message);601}602vm_direct_exit(code);603}604605void vm_perform_shutdown_actions() {606if (is_init_completed()) {607Thread* thread = Thread::current_or_null();608if (thread != NULL && thread->is_Java_thread()) {609// We are leaving the VM, set state to native (in case any OS exit610// handlers call back to the VM)611JavaThread* jt = thread->as_Java_thread();612// Must always be walkable or have no last_Java_frame when in613// thread_in_native614jt->frame_anchor()->make_walkable(jt);615jt->set_thread_state(_thread_in_native);616}617}618notify_vm_shutdown();619}620621void vm_shutdown()622{623vm_perform_shutdown_actions();624os::wait_for_keypress_at_exit();625os::shutdown();626}627628void vm_abort(bool dump_core) {629vm_perform_shutdown_actions();630os::wait_for_keypress_at_exit();631632// Flush stdout and stderr before abort.633fflush(stdout);634fflush(stderr);635636os::abort(dump_core);637ShouldNotReachHere();638}639640void vm_notify_during_cds_dumping(const char* error, const char* message) {641if (error != NULL) {642tty->print_cr("Error occurred during CDS dumping");643tty->print("%s", error);644if (message != NULL) {645tty->print_cr(": %s", message);646}647else {648tty->cr();649}650}651}652653void vm_exit_during_cds_dumping(const char* error, const char* message) {654vm_notify_during_cds_dumping(error, message);655656// Failure during CDS dumping, we don't want to dump core657vm_abort(false);658}659660void vm_notify_during_shutdown(const char* error, const char* message) {661if (error != NULL) {662tty->print_cr("Error occurred during initialization of VM");663tty->print("%s", error);664if (message != NULL) {665tty->print_cr(": %s", message);666}667else {668tty->cr();669}670}671if (ShowMessageBoxOnError && WizardMode) {672fatal("Error occurred during initialization of VM");673}674}675676void vm_exit_during_initialization() {677vm_notify_during_shutdown(NULL, NULL);678679// Failure during initialization, we don't want to dump core680vm_abort(false);681}682683void vm_exit_during_initialization(Handle exception) {684tty->print_cr("Error occurred during initialization of VM");685// If there are exceptions on this thread it must be cleared686// first and here. Any future calls to EXCEPTION_MARK requires687// that no pending exceptions exist.688JavaThread* THREAD = JavaThread::current(); // can't be NULL689if (HAS_PENDING_EXCEPTION) {690CLEAR_PENDING_EXCEPTION;691}692java_lang_Throwable::print_stack_trace(exception, tty);693tty->cr();694vm_notify_during_shutdown(NULL, NULL);695696// Failure during initialization, we don't want to dump core697vm_abort(false);698}699700void vm_exit_during_initialization(Symbol* ex, const char* message) {701ResourceMark rm;702vm_notify_during_shutdown(ex->as_C_string(), message);703704// Failure during initialization, we don't want to dump core705vm_abort(false);706}707708void vm_exit_during_initialization(const char* error, const char* message) {709vm_notify_during_shutdown(error, message);710711// Failure during initialization, we don't want to dump core712vm_abort(false);713}714715void vm_shutdown_during_initialization(const char* error, const char* message) {716vm_notify_during_shutdown(error, message);717vm_shutdown();718}719720JDK_Version JDK_Version::_current;721const char* JDK_Version::_java_version;722const char* JDK_Version::_runtime_name;723const char* JDK_Version::_runtime_version;724const char* JDK_Version::_runtime_vendor_version;725const char* JDK_Version::_runtime_vendor_vm_bug_url;726727void JDK_Version::initialize() {728assert(!_current.is_valid(), "Don't initialize twice");729730int major = VM_Version::vm_major_version();731int minor = VM_Version::vm_minor_version();732int security = VM_Version::vm_security_version();733int build = VM_Version::vm_build_number();734int patch = VM_Version::vm_patch_version();735_current = JDK_Version(major, minor, security, patch, build);736}737738void JDK_Version_init() {739JDK_Version::initialize();740}741742static int64_t encode_jdk_version(const JDK_Version& v) {743return744((int64_t)v.major_version() << (BitsPerByte * 4)) |745((int64_t)v.minor_version() << (BitsPerByte * 3)) |746((int64_t)v.security_version() << (BitsPerByte * 2)) |747((int64_t)v.patch_version() << (BitsPerByte * 1)) |748((int64_t)v.build_number() << (BitsPerByte * 0));749}750751int JDK_Version::compare(const JDK_Version& other) const {752assert(is_valid() && other.is_valid(), "Invalid version (uninitialized?)");753uint64_t e = encode_jdk_version(*this);754uint64_t o = encode_jdk_version(other);755return (e > o) ? 1 : ((e == o) ? 0 : -1);756}757758/* See JEP 223 */759void JDK_Version::to_string(char* buffer, size_t buflen) const {760assert(buffer && buflen > 0, "call with useful buffer");761size_t index = 0;762763if (!is_valid()) {764jio_snprintf(buffer, buflen, "%s", "(uninitialized)");765} else {766int rc = jio_snprintf(767&buffer[index], buflen - index, "%d.%d", _major, _minor);768if (rc == -1) return;769index += rc;770if (_patch > 0) {771rc = jio_snprintf(&buffer[index], buflen - index, ".%d.%d", _security, _patch);772if (rc == -1) return;773index += rc;774} else if (_security > 0) {775rc = jio_snprintf(&buffer[index], buflen - index, ".%d", _security);776if (rc == -1) return;777index += rc;778}779if (_build > 0) {780rc = jio_snprintf(&buffer[index], buflen - index, "+%d", _build);781if (rc == -1) return;782index += rc;783}784}785}786787788