/* * Copyright (c) 2016, 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 "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/moduleEntry.hpp" #include "classfile/packageEntry.hpp" #include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "jfr/jfr.hpp" #include "jfr/jni/jfrGetAllEventClasses.hpp" #include "jfr/recorder/checkpoint/jfrCheckpointWriter.hpp" #include "jfr/recorder/checkpoint/types/jfrTypeSet.hpp" #include "jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp" #include "jfr/recorder/checkpoint/types/jfrTypeSetWriter.hpp" #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" #include "jfr/recorder/storage/jfrBuffer.hpp" #include "jfr/utilities/jfrHashtable.hpp" #include "jfr/utilities/jfrTypes.hpp" #include "memory/iterator.hpp" #include "memory/resourceArea.hpp" #include "oops/instanceKlass.hpp" #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "memory/resourceArea.hpp" #include "utilities/accessFlags.hpp" // incremented on each checkpoint static u8 checkpoint_id = 0; // 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))) typedef const Klass* KlassPtr; typedef const PackageEntry* PkgPtr; typedef const ModuleEntry* ModPtr; typedef const ClassLoaderData* CldPtr; typedef const Method* MethodPtr; typedef const Symbol* SymbolPtr; typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr; typedef const JfrSymbolId::CStringEntry* CStringEntryPtr; static traceid module_id(PkgPtr pkg) { assert(pkg != NULL, "invariant"); ModPtr module_entry = pkg->module(); return module_entry != NULL && module_entry->is_named() ? TRACE_ID(module_entry) : 0; } static traceid package_id(KlassPtr klass) { assert(klass != NULL, "invariant"); PkgPtr pkg_entry = klass->package(); return pkg_entry == NULL ? 0 : TRACE_ID(pkg_entry); } static traceid cld_id(CldPtr cld) { assert(cld != NULL, "invariant"); return cld->is_anonymous() ? 0 : TRACE_ID(cld); } static void tag_leakp_klass_artifacts(KlassPtr k, bool class_unload) { assert(k != NULL, "invariant"); PkgPtr pkg = k->package(); if (pkg != NULL) { tag_leakp_artifact(pkg, class_unload); ModPtr module = pkg->module(); if (module != NULL) { tag_leakp_artifact(module, class_unload); } } CldPtr cld = k->class_loader_data(); assert(cld != NULL, "invariant"); if (!cld->is_anonymous()) { tag_leakp_artifact(cld, class_unload); } } class TagLeakpKlassArtifact { bool _class_unload; public: TagLeakpKlassArtifact(bool class_unload) : _class_unload(class_unload) {} bool operator()(KlassPtr klass) { if (_class_unload) { if (LEAKP_USED_THIS_EPOCH(klass)) { tag_leakp_klass_artifacts(klass, _class_unload); } } else { if (LEAKP_USED_PREV_EPOCH(klass)) { tag_leakp_klass_artifacts(klass, _class_unload); } } return true; } }; /* * In C++03, functions used as template parameters must have external linkage; * this restriction was removed in C++11. Change back to "static" and * rename functions when C++11 becomes available. * * The weird naming is an effort to decrease the risk of name clashes. */ int write__artifact__klass(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) { assert(writer != NULL, "invariant"); assert(artifacts != NULL, "invariant"); assert(k != NULL, "invariant"); KlassPtr klass = (KlassPtr)k; traceid pkg_id = 0; KlassPtr theklass = klass; if (theklass->is_objArray_klass()) { const ObjArrayKlass* obj_arr_klass = ObjArrayKlass::cast(klass); theklass = obj_arr_klass->bottom_klass(); } if (theklass->is_instance_klass()) { pkg_id = package_id(theklass); } else { assert(theklass->is_typeArray_klass(), "invariant"); } const traceid symbol_id = artifacts->mark(klass); assert(symbol_id > 0, "need to have an address for symbol!"); writer->write(TRACE_ID(klass)); writer->write(cld_id(klass->class_loader_data())); writer->write((traceid)CREATE_SYMBOL_ID(symbol_id)); writer->write(pkg_id); writer->write((s4)klass->access_flags().get_flags()); return 1; } typedef LeakPredicate LeakKlassPredicate; typedef JfrPredicatedArtifactWriterImplHost LeakKlassWriterImpl; typedef JfrArtifactWriterHost LeakKlassWriter; typedef JfrArtifactWriterImplHost KlassWriterImpl; typedef JfrArtifactWriterHost KlassWriter; int write__artifact__method(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) { assert(writer != NULL, "invariant"); assert(artifacts != NULL, "invariant"); assert(m != NULL, "invariant"); MethodPtr method = (MethodPtr)m; const traceid method_name_symbol_id = artifacts->mark(method->name()); assert(method_name_symbol_id > 0, "invariant"); const traceid method_sig_symbol_id = artifacts->mark(method->signature()); assert(method_sig_symbol_id > 0, "invariant"); KlassPtr klass = method->method_holder(); assert(klass != NULL, "invariant"); assert(METHOD_USED_ANY_EPOCH(klass), "invariant"); writer->write((u8)METHOD_ID(klass, method)); writer->write((u8)TRACE_ID(klass)); writer->write((u8)CREATE_SYMBOL_ID(method_name_symbol_id)); writer->write((u8)CREATE_SYMBOL_ID(method_sig_symbol_id)); writer->write((u2)method->access_flags().get_flags()); writer->write(const_cast(method)->is_hidden() ? (u1)1 : (u1)0); return 1; } 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"); PkgPtr pkg = (PkgPtr)p; Symbol* const pkg_name = pkg->name(); const traceid package_name_symbol_id = pkg_name != NULL ? artifacts->mark(pkg_name) : 0; assert(package_name_symbol_id > 0, "invariant"); writer->write((traceid)TRACE_ID(pkg)); writer->write((traceid)CREATE_SYMBOL_ID(package_name_symbol_id)); writer->write(module_id(pkg)); writer->write((bool)pkg->is_exported()); return 1; } typedef LeakPredicate LeakPackagePredicate; int _compare_pkg_ptr_(PkgPtr const& lhs, PkgPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; } typedef UniquePredicate PackagePredicate; typedef JfrPredicatedArtifactWriterImplHost LeakPackageWriterImpl; typedef JfrPredicatedArtifactWriterImplHost PackageWriterImpl; typedef JfrArtifactWriterHost LeakPackageWriter; typedef JfrArtifactWriterHost PackageWriter; int write__artifact__module(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* m) { assert( m != NULL, "invariant"); ModPtr entry = (ModPtr)m; Symbol* const module_name = entry->name(); const traceid module_name_symbol_id = module_name != NULL ? artifacts->mark(module_name) : 0; Symbol* const module_version = entry->version(); const traceid module_version_symbol_id = module_version != NULL ? artifacts->mark(module_version) : 0; Symbol* const module_location = entry->location(); const traceid module_location_symbol_id = module_location != NULL ? artifacts->mark(module_location) : 0; writer->write((traceid)TRACE_ID(entry)); writer->write(module_name_symbol_id == 0 ? (traceid)0 : (traceid)CREATE_SYMBOL_ID(module_name_symbol_id)); writer->write(module_version_symbol_id == 0 ? (traceid)0 : (traceid)CREATE_SYMBOL_ID(module_version_symbol_id)); writer->write(module_location_symbol_id == 0 ? (traceid)0 : (traceid)CREATE_SYMBOL_ID(module_location_symbol_id)); writer->write(cld_id(entry->loader_data())); return 1; } typedef LeakPredicate LeakModulePredicate; int _compare_mod_ptr_(ModPtr const& lhs, ModPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; } typedef UniquePredicate ModulePredicate; typedef JfrPredicatedArtifactWriterImplHost LeakModuleWriterImpl; typedef JfrPredicatedArtifactWriterImplHost ModuleWriterImpl; typedef JfrArtifactWriterHost LeakModuleWriter; typedef JfrArtifactWriterHost ModuleWriter; int write__artifact__classloader(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) { assert(c != NULL, "invariant"); CldPtr cld = (CldPtr)c; assert(!cld->is_anonymous(), "invariant"); const traceid cld_id = TRACE_ID(cld); // class loader type const Klass* class_loader_klass = cld->class_loader_klass(); if (class_loader_klass == NULL) { // (primordial) boot class loader writer->write(cld_id); // class loader instance id writer->write((traceid)0); // class loader type id (absence of) writer->write((traceid)CREATE_SYMBOL_ID(1)); // 1 maps to synthetic name -> "boot" } else { Symbol* symbol_name = cld->name(); const traceid symbol_name_id = symbol_name != NULL ? artifacts->mark(symbol_name) : 0; writer->write(cld_id); // class loader instance id writer->write(TRACE_ID(class_loader_klass)); // class loader type id writer->write(symbol_name_id == 0 ? (traceid)0 : (traceid)CREATE_SYMBOL_ID(symbol_name_id)); // class loader instance name } return 1; } typedef LeakPredicate LeakCldPredicate; int _compare_cld_ptr_(CldPtr const& lhs, CldPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; } typedef UniquePredicate CldPredicate; typedef JfrPredicatedArtifactWriterImplHost LeakCldWriterImpl; typedef JfrPredicatedArtifactWriterImplHost CldWriterImpl; typedef JfrArtifactWriterHost LeakCldWriter; typedef JfrArtifactWriterHost CldWriter; typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr; static int write__artifact__symbol__entry__(JfrCheckpointWriter* writer, SymbolEntryPtr entry) { assert(writer != NULL, "invariant"); assert(entry != NULL, "invariant"); ResourceMark rm; writer->write(CREATE_SYMBOL_ID(entry->id())); writer->write(entry->value()->as_C_string()); return 1; } int write__artifact__symbol__entry(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* e) { assert(e != NULL, "invariant"); return write__artifact__symbol__entry__(writer, (SymbolEntryPtr)e); } typedef JfrArtifactWriterImplHost SymbolEntryWriterImpl; typedef JfrArtifactWriterHost SymbolEntryWriter; typedef const JfrSymbolId::CStringEntry* CStringEntryPtr; static int write__artifact__cstring__entry__(JfrCheckpointWriter* writer, CStringEntryPtr entry) { assert(writer != NULL, "invariant"); assert(entry != NULL, "invariant"); writer->write(CREATE_SYMBOL_ID(entry->id())); writer->write(entry->value()); return 1; } int write__artifact__cstring__entry(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* e) { assert(e != NULL, "invariant"); return write__artifact__cstring__entry__(writer, (CStringEntryPtr)e); } typedef JfrArtifactWriterImplHost CStringEntryWriterImpl; typedef JfrArtifactWriterHost CStringEntryWriter; int write__artifact__klass__symbol(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* k) { assert(writer != NULL, "invariant"); assert(artifacts != NULL, "invaiant"); assert(k != NULL, "invariant"); const InstanceKlass* const ik = (const InstanceKlass*)k; if (ik->is_anonymous()) { CStringEntryPtr entry = artifacts->map_cstring(JfrSymbolId::anonymous_klass_name_hash_code(ik)); assert(entry != NULL, "invariant"); return write__artifact__cstring__entry__(writer, entry); } SymbolEntryPtr entry = artifacts->map_symbol(JfrSymbolId::regular_klass_name_hash_code(ik)); return write__artifact__symbol__entry__(writer, entry); } int _compare_traceid_(const traceid& lhs, const traceid& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; } template