# HG changeset patch # User andrew # Date 1593462626 -3600 # Node ID fb74ae5912096e3a63ff144d7ec497dfb04eae7a # Parent ae4fc0906f45a1fc3d0ea053f15b2ff3fc6e515f# Parent 1c6e1f187fdc571e5fb7eaf9ed0180ce6fe0a4a4 Merge diff -r ae4fc0906f45 -r fb74ae591209 .hgtags --- a/.hgtags Mon Apr 11 08:51:53 2016 +0200 +++ b/.hgtags Mon Jun 29 21:30:26 2020 +0100 @@ -1313,3 +1313,6 @@ f7691a80458c365b5dd754b1e117818144ed30f1 jdk8u262-b05 f7691a80458c365b5dd754b1e117818144ed30f1 jdk8u272-b00 de6565b66f9458fb97eb66483e48f159b3f39d36 jdk8u262-b06 +d20a5f399218f58f82f4f4503d24957ce7e48e60 jdk8u262-b07 +d2c2cd90513e48822648ff16016aa76577eb7ab1 jdk8u262-b08 +cf6e3496e19a2957f7d8b28bd0a033cefbf6509f jdk8u262-b09 diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/classfile/classLoader.cpp --- a/src/share/vm/classfile/classLoader.cpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/classfile/classLoader.cpp Mon Jun 29 21:30:26 2020 +0100 @@ -162,6 +162,64 @@ return (strncmp(str + (str_len - str_to_find_len), str_to_find, str_to_find_len) == 0); } +// Used to obtain the package name from a fully qualified class name. +// It is the responsibility of the caller to establish a ResourceMark. +const char* ClassLoader::package_from_name(const char* const class_name, bool* bad_class_name) { + if (class_name == NULL) { + if (bad_class_name != NULL) { + *bad_class_name = true; + } + return NULL; + } + + if (bad_class_name != NULL) { + *bad_class_name = false; + } + + const char* const last_slash = strrchr(class_name, '/'); + if (last_slash == NULL) { + // No package name + return NULL; + } + + char* class_name_ptr = (char*) class_name; + // Skip over '['s + if (*class_name_ptr == '[') { + do { + class_name_ptr++; + } while (*class_name_ptr == '['); + + // Fully qualified class names should not contain a 'L'. + // Set bad_class_name to true to indicate that the package name + // could not be obtained due to an error condition. + // In this situation, is_same_class_package returns false. + if (*class_name_ptr == 'L') { + if (bad_class_name != NULL) { + *bad_class_name = true; + } + return NULL; + } + } + + int length = last_slash - class_name_ptr; + + // A class name could have just the slash character in the name. + if (length <= 0) { + // No package name + if (bad_class_name != NULL) { + *bad_class_name = true; + } + return NULL; + } + + // drop name after last slash (including slash) + // Ex., "java/lang/String.class" => "java/lang" + char* pkg_name = NEW_RESOURCE_ARRAY(char, length + 1); + strncpy(pkg_name, class_name_ptr, length); + *(pkg_name+length) = '\0'; + + return (const char *)pkg_name; +} MetaIndex::MetaIndex(char** meta_package_names, int num_meta_package_names) { if (num_meta_package_names == 0) { diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/classfile/classLoader.hpp --- a/src/share/vm/classfile/classLoader.hpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/classfile/classLoader.hpp Mon Jun 29 21:30:26 2020 +0100 @@ -366,6 +366,11 @@ // creates a class path zip entry (returns NULL if JAR file cannot be opened) static ClassPathZipEntry* create_class_path_zip_entry(const char *apath); + // obtain package name from a fully qualified class name + // *bad_class_name is set to true if there's a problem with parsing class_name, to + // distinguish from a class_name with no package name, as both cases have a NULL return value + static const char* package_from_name(const char* const class_name, bool* bad_class_name = NULL); + // Debugging static void verify() PRODUCT_RETURN; diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.cpp --- a/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/checkpoint/jfrCheckpointManager.cpp Mon Jun 29 21:30:26 2020 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -135,6 +135,8 @@ void JfrCheckpointManager::register_full(BufferPtr t, Thread* thread) { // nothing here at the moment + assert(t != NULL, "invariant"); + assert(t->acquired_by(thread), "invariant"); assert(t->retired(), "invariant"); } diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.cpp --- a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.cpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.cpp Mon Jun 29 21:30:26 2020 +0100 @@ -51,6 +51,7 @@ // creates a unique id by combining a checkpoint relative symbol id (2^24) // with the current checkpoint id (2^40) #define CREATE_SYMBOL_ID(sym_id) (((u8)((checkpoint_id << 24) | sym_id))) +#define CREATE_PACKAGE_ID(pkg_id) (((u8)((checkpoint_id << 24) | pkg_id))) typedef const Klass* KlassPtr; typedef const ClassLoaderData* CldPtr; @@ -59,6 +60,24 @@ typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr; typedef const JfrSymbolId::CStringEntry* CStringEntryPtr; +inline uintptr_t package_name_hash(const char *s) { + uintptr_t val = 0; + while (*s != 0) { + val = *s++ + 31 * val; + } + return val; +} + +static traceid package_id(KlassPtr klass, JfrArtifactSet* artifacts) { + assert(klass != NULL, "invariant"); + char* klass_name = klass->name()->as_C_string(); // uses ResourceMark declared in JfrTypeSet::serialize() + const char* pkg_name = ClassLoader::package_from_name(klass_name, NULL); + if (pkg_name == NULL) { + return 0; + } + return CREATE_PACKAGE_ID(artifacts->markPackage(pkg_name, package_name_hash(pkg_name))); +} + static traceid cld_id(CldPtr cld) { assert(cld != NULL, "invariant"); return cld->is_anonymous() ? 0 : TRACE_ID(cld); @@ -111,7 +130,7 @@ theklass = obj_arr_klass->bottom_klass(); } if (theklass->oop_is_instance()) { - pkg_id = 0; + pkg_id = package_id(theklass, artifacts); } else { assert(theklass->oop_is_typeArray(), "invariant"); } @@ -155,6 +174,20 @@ typedef JfrArtifactWriterImplHost MethodWriterImplTarget; typedef JfrArtifactWriterHost MethodWriterImpl; +int write__artifact__package(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) { + assert(writer != NULL, "invariant"); + assert(artifacts != NULL, "invariant"); + assert(p != NULL, "invariant"); + + CStringEntryPtr entry = (CStringEntryPtr)p; + const traceid package_name_symbol_id = artifacts->mark(entry->value(), package_name_hash(entry->value())); + assert(package_name_symbol_id > 0, "invariant"); + writer->write((traceid)CREATE_PACKAGE_ID(entry->id())); + writer->write((traceid)CREATE_SYMBOL_ID(package_name_symbol_id)); + writer->write((bool)true); // exported + return 1; +} + int write__artifact__classloader(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) { assert(c != NULL, "invariant"); CldPtr cld = (CldPtr)c; @@ -436,6 +469,18 @@ do_klasses(); } +typedef JfrArtifactWriterImplHost PackageEntryWriterImpl; +typedef JfrArtifactWriterHost PackageEntryWriter; + +void JfrTypeSet::write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) { + assert(_artifacts->has_klass_entries(), "invariant"); + assert(writer != NULL, "invariant"); + // below jdk9 there is no oop for packages, so nothing to do with leakp_writer + // just write packages + PackageEntryWriter pw(writer, _artifacts, _class_unload); + _artifacts->iterate_packages(pw); +} + typedef CompositeFunctor > CldWriterWithClear; typedef CompositeFunctor CompositeCldWriter; typedef CompositeFunctor > CompositeCldWriterWithClear; @@ -685,6 +730,7 @@ // might tag an artifact to be written in a subsequent step write_klass_constants(writer, leakp_writer); if (_artifacts->has_klass_entries()) { + write_package_constants(writer, leakp_writer); write_class_loader_constants(writer, leakp_writer); write_method_constants(writer, leakp_writer); write_symbol_constants(writer, leakp_writer); diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.hpp --- a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.hpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.hpp Mon Jun 29 21:30:26 2020 +0100 @@ -51,6 +51,7 @@ static void do_class_loaders(); static void write_klass_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer); + static void write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer); static void write_class_loader_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer); static void write_method_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer); static void write_symbol_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer); diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp --- a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp Mon Jun 29 21:30:26 2020 +0100 @@ -28,9 +28,11 @@ #include "oops/oop.inline.hpp" #include "oops/symbol.hpp" -JfrSymbolId::JfrSymbolId() : _symbol_id_counter(0), _sym_table(new SymbolTable(this)), _cstring_table(new CStringTable(this)) { +JfrSymbolId::JfrSymbolId() : _symbol_id_counter(0), _sym_table(new SymbolTable(this)), + _cstring_table(new CStringTable(this)), _pkg_table(new CStringTable(this)) { assert(_sym_table != NULL, "invariant"); assert(_cstring_table != NULL, "invariant"); + assert(_pkg_table != NULL, "invariant"); initialize(); } @@ -52,6 +54,11 @@ } assert(!_cstring_table->has_entries(), "invariant"); _symbol_id_counter = 0; + assert(_pkg_table != NULL, "invariant"); + if (_pkg_table->has_entries()) { + _pkg_table->clear_entries(); + } + assert(!_pkg_table->has_entries(), "invariant"); } JfrSymbolId::~JfrSymbolId() { @@ -148,6 +155,12 @@ return _cstring_table->id(str, hash); } +traceid JfrSymbolId::markPackage(const char* name, uintptr_t hash) { + assert(name != NULL, "invariant"); + assert(_pkg_table != NULL, "invariant"); + return _pkg_table->id(name, hash); +} + bool JfrSymbolId::is_anonymous_klass(const Klass* k) { assert(k != NULL, "invariant"); return k->oop_is_instance() && ((const InstanceKlass*)k)->is_anonymous(); @@ -243,6 +256,10 @@ return _symbol_id->mark(str, hash); } +traceid JfrArtifactSet::markPackage(const char* const name, uintptr_t hash) { + return _symbol_id->markPackage(name, hash); +} + const JfrSymbolId::SymbolEntry* JfrArtifactSet::map_symbol(const Symbol* symbol) const { return _symbol_id->map_symbol(symbol); } diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp --- a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp Mon Jun 29 21:30:26 2020 +0100 @@ -230,9 +230,10 @@ typedef SymbolTable::HashEntry SymbolEntry; typedef CStringTable::HashEntry CStringEntry; private: + traceid _symbol_id_counter; SymbolTable* _sym_table; CStringTable* _cstring_table; - traceid _symbol_id_counter; + CStringTable* _pkg_table; // hashtable(s) callbacks void assign_id(SymbolEntry* entry); @@ -257,6 +258,12 @@ traceid mark(const Klass* k); traceid mark(const Symbol* symbol); traceid mark(const char* str, uintptr_t hash); + traceid markPackage(const char* name, uintptr_t hash); + + template + void iterate_packages(T& functor) { + _pkg_table->iterate_entry(functor); + } const SymbolEntry* map_symbol(const Symbol* symbol) const; const SymbolEntry* map_symbol(uintptr_t hash) const; @@ -334,6 +341,8 @@ traceid mark(const char* const str, uintptr_t hash); traceid mark_anonymous_klass_name(const Klass* klass); + traceid markPackage(const char* const name, uintptr_t hash); + const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const; const JfrSymbolId::SymbolEntry* map_symbol(uintptr_t hash) const; const JfrSymbolId::CStringEntry* map_cstring(uintptr_t hash) const; @@ -360,6 +369,11 @@ void iterate_cstrings(T& functor) { _symbol_id->iterate_cstrings(functor); } + + template + void iterate_packages(T& functor) { + _symbol_id->iterate_packages(functor); + } }; class KlassArtifactRegistrator { diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/storage/jfrBuffer.cpp --- a/src/share/vm/jfr/recorder/storage/jfrBuffer.cpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/storage/jfrBuffer.cpp Mon Jun 29 21:30:26 2020 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2019, 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 @@ -137,6 +137,14 @@ _identity = NULL; } +bool JfrBuffer::acquired_by(const void* id) const { + return identity() == id; +} + +bool JfrBuffer::acquired_by_self() const { + return acquired_by(Thread::current()); +} + #ifdef ASSERT static bool validate_to(const JfrBuffer* const to, size_t size) { assert(to != NULL, "invariant"); @@ -154,10 +162,6 @@ assert(t->top() + size <= t->pos(), "invariant"); return true; } - -bool JfrBuffer::acquired_by_self() const { - return identity() == Thread::current(); -} #endif // ASSERT void JfrBuffer::move(JfrBuffer* const to, size_t size) { @@ -184,7 +188,6 @@ set_concurrent_top(start()); } -// flags enum FLAG { RETIRED = 1, TRANSIENT = 2, diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/storage/jfrBuffer.hpp --- a/src/share/vm/jfr/recorder/storage/jfrBuffer.hpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/storage/jfrBuffer.hpp Mon Jun 29 21:30:26 2020 +0100 @@ -57,7 +57,6 @@ u4 _size; const u1* stable_top() const; - void clear_flags(); public: JfrBuffer(); @@ -150,6 +149,8 @@ void acquire(const void* id); bool try_acquire(const void* id); + bool acquired_by(const void* id) const; + bool acquired_by_self() const; void release(); void move(JfrBuffer* const to, size_t size); @@ -166,8 +167,6 @@ bool retired() const; void set_retired(); void clear_retired(); - - debug_only(bool acquired_by_self() const;) }; class JfrAgeNode : public JfrBuffer { diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/storage/jfrMemorySpace.inline.hpp --- a/src/share/vm/jfr/recorder/storage/jfrMemorySpace.inline.hpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/storage/jfrMemorySpace.inline.hpp Mon Jun 29 21:30:26 2020 +0100 @@ -346,19 +346,19 @@ template inline bool ReleaseOp::process(typename Mspace::Type* t) { assert(t != NULL, "invariant"); - if (t->retired() || t->try_acquire(_thread)) { - if (t->transient()) { - if (_release_full) { - mspace_release_full_critical(t, _mspace); - } else { - mspace_release_free_critical(t, _mspace); - } - return true; + // assumes some means of exclusive access to t + if (t->transient()) { + if (_release_full) { + mspace_release_full_critical(t, _mspace); + } else { + mspace_release_free_critical(t, _mspace); } - t->reinitialize(); - assert(t->empty(), "invariant"); - t->release(); // publish + return true; } + t->reinitialize(); + assert(t->empty(), "invariant"); + assert(!t->retired(), "invariant"); + t->release(); // publish return true; } diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/storage/jfrStorage.cpp --- a/src/share/vm/jfr/recorder/storage/jfrStorage.cpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/storage/jfrStorage.cpp Mon Jun 29 21:30:26 2020 +0100 @@ -340,9 +340,9 @@ void JfrStorage::register_full(BufferPtr buffer, Thread* thread) { assert(buffer != NULL, "invariant"); assert(buffer->retired(), "invariant"); + assert(buffer->acquired_by(thread), "invariant"); if (!full_buffer_registration(buffer, _age_mspace, control(), thread)) { handle_registration_failure(buffer); - buffer->release(); } if (control().should_post_buffer_full_message()) { _post_box.post(MSG_FULLBUFFER); @@ -377,8 +377,8 @@ } } assert(buffer->empty(), "invariant"); + assert(buffer->identity() != NULL, "invariant"); control().increment_dead(); - buffer->release(); buffer->set_retired(); } @@ -733,13 +733,14 @@ Scavenger(JfrStorageControl& control, Mspace* mspace) : _control(control), _mspace(mspace), _count(0), _amount(0) {} bool process(Type* t) { if (t->retired()) { + assert(t->identity() != NULL, "invariant"); + assert(t->empty(), "invariant"); assert(!t->transient(), "invariant"); assert(!t->lease(), "invariant"); - assert(t->empty(), "invariant"); - assert(t->identity() == NULL, "invariant"); ++_count; _amount += t->total_size(); t->clear_retired(); + t->release(); _control.decrement_dead(); mspace_release_full_critical(t, _mspace); } diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/storage/jfrStorageUtils.hpp --- a/src/share/vm/jfr/recorder/storage/jfrStorageUtils.hpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/storage/jfrStorageUtils.hpp Mon Jun 29 21:30:26 2020 +0100 @@ -92,7 +92,6 @@ size_t processed() const { return ConcurrentWriteOp::processed(); } }; - template class MutexedWriteOp { private: @@ -104,6 +103,15 @@ size_t processed() const { return _operation.processed(); } }; +template +class ExclusiveOp : private MutexedWriteOp { + public: + typedef typename Operation::Type Type; + ExclusiveOp(Operation& operation) : MutexedWriteOp(operation) {} + bool process(Type* t); + size_t processed() const { return MutexedWriteOp::processed(); } +}; + enum jfr_operation_mode { mutexed = 1, concurrent diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/storage/jfrStorageUtils.inline.hpp --- a/src/share/vm/jfr/recorder/storage/jfrStorageUtils.inline.hpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/storage/jfrStorageUtils.inline.hpp Mon Jun 29 21:30:26 2020 +0100 @@ -26,6 +26,7 @@ #define SHARE_VM_JFR_RECORDER_STORAGE_JFRSTORAGEUTILS_INLINE_HPP #include "jfr/recorder/storage/jfrStorageUtils.hpp" +#include "runtime/thread.inline.hpp" template inline bool UnBufferedWriteToChunk::write(T* t, const u1* data, size_t size) { @@ -75,6 +76,28 @@ return result; } +template +static void retired_sensitive_acquire(Type* t) { + assert(t != NULL, "invariant"); + if (t->retired()) { + return; + } + Thread* const thread = Thread::current(); + while (!t->try_acquire(thread)) { + if (t->retired()) { + return; + } + } +} + +template +inline bool ExclusiveOp::process(typename Operation::Type* t) { + retired_sensitive_acquire(t); + assert(t->acquired_by_self() || t->retired(), "invariant"); + // User is required to ensure proper release of the acquisition + return MutexedWriteOp::process(t); +} + template inline bool DiscardOp::process(typename Operation::Type* t) { assert(t != NULL, "invariant"); diff -r ae4fc0906f45 -r fb74ae591209 src/share/vm/jfr/recorder/stringpool/jfrStringPool.cpp --- a/src/share/vm/jfr/recorder/stringpool/jfrStringPool.cpp Mon Apr 11 08:51:53 2016 +0200 +++ b/src/share/vm/jfr/recorder/stringpool/jfrStringPool.cpp Mon Jun 29 21:30:26 2020 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2019, 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 @@ -139,93 +139,76 @@ return current_epoch; } -class StringPoolWriteOp { +template