8245167: Top package in method profiling shows null in JMC jdk8u262-b07

Mon, 15 Jun 2020 14:08:11 +0300

author
apetushkov
date
Mon, 15 Jun 2020 14:08:11 +0300
changeset 9926
d20a5f399218
parent 9925
30fb8c8cceb9
child 9927
b273df69fbfe

8245167: Top package in method profiling shows null in JMC
Reviewed-by: neugens
Contributed-by: asemenov@azul.com

src/share/vm/classfile/classLoader.cpp file | annotate | diff | comparison | revisions
src/share/vm/classfile/classLoader.hpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.cpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.hpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp file | annotate | diff | comparison | revisions
src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/classfile/classLoader.cpp	Fri Jun 12 02:59:56 2020 +0100
     1.2 +++ b/src/share/vm/classfile/classLoader.cpp	Mon Jun 15 14:08:11 2020 +0300
     1.3 @@ -162,6 +162,64 @@
     1.4    return (strncmp(str + (str_len - str_to_find_len), str_to_find, str_to_find_len) == 0);
     1.5  }
     1.6  
     1.7 +// Used to obtain the package name from a fully qualified class name.
     1.8 +// It is the responsibility of the caller to establish a ResourceMark.
     1.9 +const char* ClassLoader::package_from_name(const char* const class_name, bool* bad_class_name) {
    1.10 +  if (class_name == NULL) {
    1.11 +    if (bad_class_name != NULL) {
    1.12 +      *bad_class_name = true;
    1.13 +    }
    1.14 +    return NULL;
    1.15 +  }
    1.16 +
    1.17 +  if (bad_class_name != NULL) {
    1.18 +    *bad_class_name = false;
    1.19 +  }
    1.20 +
    1.21 +  const char* const last_slash = strrchr(class_name, '/');
    1.22 +  if (last_slash == NULL) {
    1.23 +    // No package name
    1.24 +    return NULL;
    1.25 +  }
    1.26 +
    1.27 +  char* class_name_ptr = (char*) class_name;
    1.28 +  // Skip over '['s
    1.29 +  if (*class_name_ptr == '[') {
    1.30 +    do {
    1.31 +      class_name_ptr++;
    1.32 +    } while (*class_name_ptr == '[');
    1.33 +
    1.34 +    // Fully qualified class names should not contain a 'L'.
    1.35 +    // Set bad_class_name to true to indicate that the package name
    1.36 +    // could not be obtained due to an error condition.
    1.37 +    // In this situation, is_same_class_package returns false.
    1.38 +    if (*class_name_ptr == 'L') {
    1.39 +      if (bad_class_name != NULL) {
    1.40 +        *bad_class_name = true;
    1.41 +      }
    1.42 +      return NULL;
    1.43 +    }
    1.44 +  }
    1.45 +
    1.46 +  int length = last_slash - class_name_ptr;
    1.47 +
    1.48 +  // A class name could have just the slash character in the name.
    1.49 +  if (length <= 0) {
    1.50 +    // No package name
    1.51 +    if (bad_class_name != NULL) {
    1.52 +      *bad_class_name = true;
    1.53 +    }
    1.54 +    return NULL;
    1.55 +  }
    1.56 +
    1.57 +  // drop name after last slash (including slash)
    1.58 +  // Ex., "java/lang/String.class" => "java/lang"
    1.59 +  char* pkg_name = NEW_RESOURCE_ARRAY(char, length + 1);
    1.60 +  strncpy(pkg_name, class_name_ptr, length);
    1.61 +  *(pkg_name+length) = '\0';
    1.62 +
    1.63 +  return (const char *)pkg_name;
    1.64 +}
    1.65  
    1.66  MetaIndex::MetaIndex(char** meta_package_names, int num_meta_package_names) {
    1.67    if (num_meta_package_names == 0) {
     2.1 --- a/src/share/vm/classfile/classLoader.hpp	Fri Jun 12 02:59:56 2020 +0100
     2.2 +++ b/src/share/vm/classfile/classLoader.hpp	Mon Jun 15 14:08:11 2020 +0300
     2.3 @@ -366,6 +366,11 @@
     2.4    // creates a class path zip entry (returns NULL if JAR file cannot be opened)
     2.5    static ClassPathZipEntry* create_class_path_zip_entry(const char *apath);
     2.6  
     2.7 +  // obtain package name from a fully qualified class name
     2.8 +  // *bad_class_name is set to true if there's a problem with parsing class_name, to
     2.9 +  // distinguish from a class_name with no package name, as both cases have a NULL return value
    2.10 +  static const char* package_from_name(const char* const class_name, bool* bad_class_name = NULL);
    2.11 +
    2.12    // Debugging
    2.13    static void verify()              PRODUCT_RETURN;
    2.14  
     3.1 --- a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Fri Jun 12 02:59:56 2020 +0100
     3.2 +++ b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.cpp	Mon Jun 15 14:08:11 2020 +0300
     3.3 @@ -52,6 +52,7 @@
     3.4  // creates a unique id by combining a checkpoint relative symbol id (2^24)
     3.5  // with the current checkpoint id (2^40)
     3.6  #define CREATE_SYMBOL_ID(sym_id) (((u8)((checkpoint_id << 24) | sym_id)))
     3.7 +#define CREATE_PACKAGE_ID(pkg_id) (((u8)((checkpoint_id << 24) | pkg_id)))
     3.8  
     3.9  typedef const Klass* KlassPtr;
    3.10  // XXX typedef const PackageEntry* PkgPtr;
    3.11 @@ -61,12 +62,23 @@
    3.12  typedef const JfrSymbolId::SymbolEntry* SymbolEntryPtr;
    3.13  typedef const JfrSymbolId::CStringEntry* CStringEntryPtr;
    3.14  
    3.15 -// XXX
    3.16 -// static traceid package_id(KlassPtr klass) {
    3.17 -//   assert(klass != NULL, "invariant");
    3.18 -//   PkgPtr pkg_entry = klass->package();
    3.19 -//   return pkg_entry == NULL ? 0 : TRACE_ID(pkg_entry);
    3.20 -// }
    3.21 +inline uintptr_t package_name_hash(const char *s) {
    3.22 +  uintptr_t val = 0;
    3.23 +  while (*s != 0) {
    3.24 +    val = *s++ + 31 * val;
    3.25 +  }
    3.26 +  return val;
    3.27 +}
    3.28 +
    3.29 +static traceid package_id(KlassPtr klass, JfrArtifactSet* artifacts) {
    3.30 +  assert(klass != NULL, "invariant");
    3.31 +  char* klass_name = klass->name()->as_C_string(); // uses ResourceMark declared in JfrTypeSet::serialize()
    3.32 +  const char* pkg_name = ClassLoader::package_from_name(klass_name, NULL);
    3.33 +  if (pkg_name == NULL) {
    3.34 +    return 0;
    3.35 +  }
    3.36 +  return CREATE_PACKAGE_ID(artifacts->markPackage(pkg_name, package_name_hash(pkg_name)));
    3.37 +}
    3.38  
    3.39  static traceid cld_id(CldPtr cld) {
    3.40    assert(cld != NULL, "invariant");
    3.41 @@ -125,7 +137,7 @@
    3.42      theklass = obj_arr_klass->bottom_klass();
    3.43    }
    3.44    if (theklass->oop_is_instance()) {
    3.45 -    pkg_id = 0; // XXX package_id(theklass);
    3.46 +    pkg_id = package_id(theklass, artifacts);
    3.47    } else {
    3.48      assert(theklass->oop_is_typeArray(), "invariant");
    3.49    }
    3.50 @@ -169,28 +181,19 @@
    3.51  typedef JfrArtifactWriterImplHost<MethodPtr, write__artifact__method> MethodWriterImplTarget;
    3.52  typedef JfrArtifactWriterHost<MethodWriterImplTarget, TYPE_METHOD> MethodWriterImpl;
    3.53  
    3.54 -// XXX
    3.55 -// int write__artifact__package(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) {
    3.56 -//   assert(writer != NULL, "invariant");
    3.57 -//   assert(artifacts != NULL, "invariant");
    3.58 -//   assert(p != NULL, "invariant");
    3.59 -//   PkgPtr pkg = (PkgPtr)p;
    3.60 -//   Symbol* const pkg_name = pkg->name();
    3.61 -//   const traceid package_name_symbol_id = pkg_name != NULL ? artifacts->mark(pkg_name) : 0;
    3.62 -//   assert(package_name_symbol_id > 0, "invariant");
    3.63 -//   writer->write((traceid)TRACE_ID(pkg));
    3.64 -//   writer->write((traceid)CREATE_SYMBOL_ID(package_name_symbol_id));
    3.65 -//   writer->write((bool)pkg->is_exported());
    3.66 -//   return 1;
    3.67 -// }
    3.68 +int write__artifact__package(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* p) {
    3.69 +  assert(writer != NULL, "invariant");
    3.70 +  assert(artifacts != NULL, "invariant");
    3.71 +  assert(p != NULL, "invariant");
    3.72  
    3.73 -// typedef LeakPredicate<PkgPtr> LeakPackagePredicate;
    3.74 -// int _compare_pkg_ptr_(PkgPtr const& lhs, PkgPtr const& rhs) { return lhs > rhs ? 1 : (lhs < rhs) ? -1 : 0; }
    3.75 -// typedef UniquePredicate<PkgPtr, _compare_pkg_ptr_> PackagePredicate;
    3.76 -// typedef JfrPredicatedArtifactWriterImplHost<PkgPtr, LeakPackagePredicate, write__artifact__package> LeakPackageWriterImpl;
    3.77 -// typedef JfrPredicatedArtifactWriterImplHost<PkgPtr, PackagePredicate, write__artifact__package> PackageWriterImpl;
    3.78 -// typedef JfrArtifactWriterHost<LeakPackageWriterImpl, TYPE_PACKAGE> LeakPackageWriter;
    3.79 -// typedef JfrArtifactWriterHost<PackageWriterImpl, TYPE_PACKAGE> PackageWriter;
    3.80 +  CStringEntryPtr entry = (CStringEntryPtr)p;
    3.81 +  const traceid package_name_symbol_id = artifacts->mark(entry->value(), package_name_hash(entry->value()));
    3.82 +  assert(package_name_symbol_id > 0, "invariant");
    3.83 +  writer->write((traceid)CREATE_PACKAGE_ID(entry->id()));
    3.84 +  writer->write((traceid)CREATE_SYMBOL_ID(package_name_symbol_id));
    3.85 +  writer->write((bool)true); // exported
    3.86 +  return 1;
    3.87 +}
    3.88  
    3.89  int write__artifact__classloader(JfrCheckpointWriter* writer, JfrArtifactSet* artifacts, const void* c) {
    3.90    assert(c != NULL, "invariant");
    3.91 @@ -525,99 +528,17 @@
    3.92    do_klasses();
    3.93  }
    3.94  
    3.95 -// XXX
    3.96 -// typedef CompositeFunctor<PkgPtr,
    3.97 -//                          PackageWriter,
    3.98 -//                          ClearArtifact<PkgPtr> > PackageWriterWithClear;
    3.99 +typedef JfrArtifactWriterImplHost<CStringEntryPtr, write__artifact__package> PackageEntryWriterImpl;
   3.100 +typedef JfrArtifactWriterHost<PackageEntryWriterImpl, TYPE_PACKAGE> PackageEntryWriter;
   3.101  
   3.102 -// typedef CompositeFunctor<PkgPtr,
   3.103 -//                          LeakPackageWriter,
   3.104 -//                          PackageWriter> CompositePackageWriter;
   3.105 -
   3.106 -// typedef CompositeFunctor<PkgPtr,
   3.107 -//                          CompositePackageWriter,
   3.108 -//                          ClearArtifact<PkgPtr> > CompositePackageWriterWithClear;
   3.109 -
   3.110 -// class PackageFieldSelector {
   3.111 -//  public:
   3.112 -//   typedef PkgPtr TypePtr;
   3.113 -//   static TypePtr select(KlassPtr klass) {
   3.114 -//     assert(klass != NULL, "invariant");
   3.115 -//     return ((InstanceKlass*)klass)->package();
   3.116 -//   }
   3.117 -// };
   3.118 -
   3.119 -// typedef KlassToFieldEnvelope<PackageFieldSelector,
   3.120 -//                              PackageWriterWithClear> KlassPackageWriterWithClear;
   3.121 -
   3.122 -// typedef KlassToFieldEnvelope<PackageFieldSelector,
   3.123 -//                              CompositePackageWriterWithClear> KlassCompositePackageWriterWithClear;
   3.124 -
   3.125 -// typedef JfrArtifactCallbackHost<PkgPtr, PackageWriterWithClear> PackageCallback;
   3.126 -// typedef JfrArtifactCallbackHost<PkgPtr, CompositePackageWriterWithClear> CompositePackageCallback;
   3.127 -
   3.128 -// /*
   3.129 -//  * Composite operation
   3.130 -//  *
   3.131 -//  * LeakpPackageWriter ->
   3.132 -//  *   PackageWriter ->
   3.133 -//  *     ClearArtifact<PackageEntry>
   3.134 -//  *
   3.135 -//  */
   3.136 -// void JfrTypeSet::write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
   3.137 -//   assert(_artifacts->has_klass_entries(), "invariant");
   3.138 -//   ClearArtifact<PkgPtr> clear(_class_unload);
   3.139 -//   PackageWriter pw(writer, _artifacts, _class_unload);
   3.140 -//   if (leakp_writer == NULL) {
   3.141 -//     PackageWriterWithClear pwwc(&pw, &clear);
   3.142 -//     KlassPackageWriterWithClear kpwwc(&pwwc);
   3.143 -//     _artifacts->iterate_klasses(kpwwc);
   3.144 -//     PackageCallback callback(&pwwc);
   3.145 -//     _subsystem_callback = &callback;
   3.146 -//     do_packages();
   3.147 -//     return;
   3.148 -//   }
   3.149 -//   LeakPackageWriter lpw(leakp_writer, _artifacts, _class_unload);
   3.150 -//   CompositePackageWriter cpw(&lpw, &pw);
   3.151 -//   CompositePackageWriterWithClear cpwwc(&cpw, &clear);
   3.152 -//   KlassCompositePackageWriterWithClear ckpw(&cpwwc);
   3.153 -//   _artifacts->iterate_klasses(ckpw);
   3.154 -//   CompositePackageCallback callback(&cpwwc);
   3.155 -//   _subsystem_callback = &callback;
   3.156 -//   do_packages();
   3.157 -// }
   3.158 -
   3.159 -// typedef CompositeFunctor<ModPtr,
   3.160 -//                          ModuleWriter,
   3.161 -//                          ClearArtifact<ModPtr> > ModuleWriterWithClear;
   3.162 -
   3.163 -// typedef CompositeFunctor<ModPtr,
   3.164 -//                          LeakModuleWriter,
   3.165 -//                          ModuleWriter> CompositeModuleWriter;
   3.166 -
   3.167 -// typedef CompositeFunctor<ModPtr,
   3.168 -//                          CompositeModuleWriter,
   3.169 -//                          ClearArtifact<ModPtr> > CompositeModuleWriterWithClear;
   3.170 -
   3.171 -// typedef JfrArtifactCallbackHost<ModPtr, ModuleWriterWithClear> ModuleCallback;
   3.172 -// typedef JfrArtifactCallbackHost<ModPtr, CompositeModuleWriterWithClear> CompositeModuleCallback;
   3.173 -
   3.174 -// XXX
   3.175 -// class ModuleFieldSelector {
   3.176 -//  public:
   3.177 -//   typedef ModPtr TypePtr;
   3.178 -//   static TypePtr select(KlassPtr klass) {
   3.179 -//     assert(klass != NULL, "invariant");
   3.180 -//     PkgPtr pkg = klass->package();
   3.181 -//     return pkg != NULL ? pkg->module() : NULL;
   3.182 -//   }
   3.183 -// };
   3.184 -
   3.185 -// typedef KlassToFieldEnvelope<ModuleFieldSelector,
   3.186 -//                              ModuleWriterWithClear> KlassModuleWriterWithClear;
   3.187 -
   3.188 -// typedef KlassToFieldEnvelope<ModuleFieldSelector,
   3.189 -//                              CompositeModuleWriterWithClear> KlassCompositeModuleWriterWithClear;
   3.190 +void JfrTypeSet::write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer) {
   3.191 +  assert(_artifacts->has_klass_entries(), "invariant");
   3.192 +  assert(writer != NULL, "invariant");
   3.193 +  // below jdk9 there is no oop for packages, so nothing to do with leakp_writer
   3.194 +  // just write packages
   3.195 +  PackageEntryWriter pw(writer, _artifacts, _class_unload);
   3.196 +  _artifacts->iterate_packages(pw);
   3.197 +}
   3.198  
   3.199  typedef CompositeFunctor<CldPtr, CldWriter, ClearArtifact<CldPtr> > CldWriterWithClear;
   3.200  typedef CompositeFunctor<CldPtr, LeakCldWriter, CldWriter> CompositeCldWriter;
   3.201 @@ -892,7 +813,7 @@
   3.202    // might tag an artifact to be written in a subsequent step
   3.203    write_klass_constants(writer, leakp_writer);
   3.204    if (_artifacts->has_klass_entries()) {
   3.205 -// XXX    write_package_constants(writer, leakp_writer);
   3.206 +    write_package_constants(writer, leakp_writer);
   3.207      write_class_loader_constants(writer, leakp_writer);
   3.208      write_method_constants(writer, leakp_writer);
   3.209      write_symbol_constants(writer, leakp_writer);
     4.1 --- a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.hpp	Fri Jun 12 02:59:56 2020 +0100
     4.2 +++ b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSet.hpp	Mon Jun 15 14:08:11 2020 +0300
     4.3 @@ -58,7 +58,7 @@
     4.4    static void do_class_loaders();
     4.5  
     4.6    static void write_klass_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
     4.7 -// XXX  static void write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
     4.8 +  static void write_package_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
     4.9    static void write_class_loader_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
    4.10    static void write_method_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
    4.11    static void write_symbol_constants(JfrCheckpointWriter* writer, JfrCheckpointWriter* leakp_writer);
     5.1 --- a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp	Fri Jun 12 02:59:56 2020 +0100
     5.2 +++ b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.cpp	Mon Jun 15 14:08:11 2020 +0300
     5.3 @@ -28,9 +28,11 @@
     5.4  #include "oops/oop.inline.hpp"
     5.5  #include "oops/symbol.hpp"
     5.6  
     5.7 -JfrSymbolId::JfrSymbolId() : _symbol_id_counter(0), _sym_table(new SymbolTable(this)), _cstring_table(new CStringTable(this)) {
     5.8 +JfrSymbolId::JfrSymbolId() : _symbol_id_counter(0), _sym_table(new SymbolTable(this)),
     5.9 +        _cstring_table(new CStringTable(this)), _pkg_table(new CStringTable(this)) {
    5.10    assert(_sym_table != NULL, "invariant");
    5.11    assert(_cstring_table != NULL, "invariant");
    5.12 +  assert(_pkg_table != NULL, "invariant");
    5.13    initialize();
    5.14  }
    5.15  
    5.16 @@ -52,6 +54,11 @@
    5.17    }
    5.18    assert(!_cstring_table->has_entries(), "invariant");
    5.19    _symbol_id_counter = 0;
    5.20 +  assert(_pkg_table != NULL, "invariant");
    5.21 +  if (_pkg_table->has_entries()) {
    5.22 +    _pkg_table->clear_entries();
    5.23 +  }
    5.24 +  assert(!_pkg_table->has_entries(), "invariant");
    5.25  }
    5.26  
    5.27  JfrSymbolId::~JfrSymbolId() {
    5.28 @@ -148,6 +155,12 @@
    5.29    return _cstring_table->id(str, hash);
    5.30  }
    5.31  
    5.32 +traceid JfrSymbolId::markPackage(const char* name, uintptr_t hash) {
    5.33 +  assert(name != NULL, "invariant");
    5.34 +  assert(_pkg_table != NULL, "invariant");
    5.35 +  return _pkg_table->id(name, hash);
    5.36 +}
    5.37 +
    5.38  bool JfrSymbolId::is_anonymous_klass(const Klass* k) {
    5.39    assert(k != NULL, "invariant");
    5.40    return k->oop_is_instance() && ((const InstanceKlass*)k)->is_anonymous();
    5.41 @@ -243,6 +256,10 @@
    5.42    return _symbol_id->mark(str, hash);
    5.43  }
    5.44  
    5.45 +traceid JfrArtifactSet::markPackage(const char* const name, uintptr_t hash) {
    5.46 +  return _symbol_id->markPackage(name, hash);
    5.47 +}
    5.48 +
    5.49  const JfrSymbolId::SymbolEntry* JfrArtifactSet::map_symbol(const Symbol* symbol) const {
    5.50    return _symbol_id->map_symbol(symbol);
    5.51  }
     6.1 --- a/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Fri Jun 12 02:59:56 2020 +0100
     6.2 +++ b/src/share/vm/jfr/recorder/checkpoint/types/jfrTypeSetUtils.hpp	Mon Jun 15 14:08:11 2020 +0300
     6.3 @@ -230,9 +230,10 @@
     6.4    typedef SymbolTable::HashEntry SymbolEntry;
     6.5    typedef CStringTable::HashEntry CStringEntry;
     6.6   private:
     6.7 +  traceid _symbol_id_counter;
     6.8    SymbolTable* _sym_table;
     6.9    CStringTable* _cstring_table;
    6.10 -  traceid _symbol_id_counter;
    6.11 +  CStringTable* _pkg_table;
    6.12  
    6.13    // hashtable(s) callbacks
    6.14    void assign_id(SymbolEntry* entry);
    6.15 @@ -257,6 +258,12 @@
    6.16    traceid mark(const Klass* k);
    6.17    traceid mark(const Symbol* symbol);
    6.18    traceid mark(const char* str, uintptr_t hash);
    6.19 +  traceid markPackage(const char* name, uintptr_t hash);
    6.20 +
    6.21 +  template <typename T>
    6.22 +  void iterate_packages(T& functor) {
    6.23 +    _pkg_table->iterate_entry(functor);
    6.24 +  }
    6.25  
    6.26    const SymbolEntry* map_symbol(const Symbol* symbol) const;
    6.27    const SymbolEntry* map_symbol(uintptr_t hash) const;
    6.28 @@ -334,6 +341,8 @@
    6.29    traceid mark(const char* const str, uintptr_t hash);
    6.30    traceid mark_anonymous_klass_name(const Klass* klass);
    6.31  
    6.32 +  traceid markPackage(const char* const name, uintptr_t hash);
    6.33 +
    6.34    const JfrSymbolId::SymbolEntry* map_symbol(const Symbol* symbol) const;
    6.35    const JfrSymbolId::SymbolEntry* map_symbol(uintptr_t hash) const;
    6.36    const JfrSymbolId::CStringEntry* map_cstring(uintptr_t hash) const;
    6.37 @@ -360,6 +369,11 @@
    6.38    void iterate_cstrings(T& functor) {
    6.39      _symbol_id->iterate_cstrings(functor);
    6.40    }
    6.41 +
    6.42 +  template <typename T>
    6.43 +  void iterate_packages(T& functor) {
    6.44 +    _symbol_id->iterate_packages(functor);
    6.45 +  }
    6.46  };
    6.47  
    6.48  class KlassArtifactRegistrator {

mercurial