src/share/vm/prims/jvmtiTagMap.cpp

changeset 0
f90c822e73f8
child 6876
710a3c8b516e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/prims/jvmtiTagMap.cpp	Wed Apr 27 01:25:04 2016 +0800
     1.3 @@ -0,0 +1,3380 @@
     1.4 +/*
     1.5 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +#include "precompiled.hpp"
    1.29 +#include "classfile/symbolTable.hpp"
    1.30 +#include "classfile/systemDictionary.hpp"
    1.31 +#include "classfile/vmSymbols.hpp"
    1.32 +#include "jvmtifiles/jvmtiEnv.hpp"
    1.33 +#include "oops/instanceMirrorKlass.hpp"
    1.34 +#include "oops/objArrayKlass.hpp"
    1.35 +#include "oops/oop.inline2.hpp"
    1.36 +#include "prims/jvmtiEventController.hpp"
    1.37 +#include "prims/jvmtiEventController.inline.hpp"
    1.38 +#include "prims/jvmtiExport.hpp"
    1.39 +#include "prims/jvmtiImpl.hpp"
    1.40 +#include "prims/jvmtiTagMap.hpp"
    1.41 +#include "runtime/biasedLocking.hpp"
    1.42 +#include "runtime/javaCalls.hpp"
    1.43 +#include "runtime/jniHandles.hpp"
    1.44 +#include "runtime/mutex.hpp"
    1.45 +#include "runtime/mutexLocker.hpp"
    1.46 +#include "runtime/reflectionUtils.hpp"
    1.47 +#include "runtime/vframe.hpp"
    1.48 +#include "runtime/vmThread.hpp"
    1.49 +#include "runtime/vm_operations.hpp"
    1.50 +#include "services/serviceUtil.hpp"
    1.51 +#include "utilities/macros.hpp"
    1.52 +#if INCLUDE_ALL_GCS
    1.53 +#include "gc_implementation/parallelScavenge/parallelScavengeHeap.hpp"
    1.54 +#endif // INCLUDE_ALL_GCS
    1.55 +
    1.56 +// JvmtiTagHashmapEntry
    1.57 +//
    1.58 +// Each entry encapsulates a reference to the tagged object
    1.59 +// and the tag value. In addition an entry includes a next pointer which
    1.60 +// is used to chain entries together.
    1.61 +
    1.62 +class JvmtiTagHashmapEntry : public CHeapObj<mtInternal> {
    1.63 + private:
    1.64 +  friend class JvmtiTagMap;
    1.65 +
    1.66 +  oop _object;                          // tagged object
    1.67 +  jlong _tag;                           // the tag
    1.68 +  JvmtiTagHashmapEntry* _next;          // next on the list
    1.69 +
    1.70 +  inline void init(oop object, jlong tag) {
    1.71 +    _object = object;
    1.72 +    _tag = tag;
    1.73 +    _next = NULL;
    1.74 +  }
    1.75 +
    1.76 +  // constructor
    1.77 +  JvmtiTagHashmapEntry(oop object, jlong tag)         { init(object, tag); }
    1.78 +
    1.79 + public:
    1.80 +
    1.81 +  // accessor methods
    1.82 +  inline oop object() const                           { return _object; }
    1.83 +  inline oop* object_addr()                           { return &_object; }
    1.84 +  inline jlong tag() const                            { return _tag; }
    1.85 +
    1.86 +  inline void set_tag(jlong tag) {
    1.87 +    assert(tag != 0, "can't be zero");
    1.88 +    _tag = tag;
    1.89 +  }
    1.90 +
    1.91 +  inline JvmtiTagHashmapEntry* next() const             { return _next; }
    1.92 +  inline void set_next(JvmtiTagHashmapEntry* next)      { _next = next; }
    1.93 +};
    1.94 +
    1.95 +
    1.96 +// JvmtiTagHashmap
    1.97 +//
    1.98 +// A hashmap is essentially a table of pointers to entries. Entries
    1.99 +// are hashed to a location, or position in the table, and then
   1.100 +// chained from that location. The "key" for hashing is address of
   1.101 +// the object, or oop. The "value" is the tag value.
   1.102 +//
   1.103 +// A hashmap maintains a count of the number entries in the hashmap
   1.104 +// and resizes if the number of entries exceeds a given threshold.
   1.105 +// The threshold is specified as a percentage of the size - for
   1.106 +// example a threshold of 0.75 will trigger the hashmap to resize
   1.107 +// if the number of entries is >75% of table size.
   1.108 +//
   1.109 +// A hashmap provides functions for adding, removing, and finding
   1.110 +// entries. It also provides a function to iterate over all entries
   1.111 +// in the hashmap.
   1.112 +
   1.113 +class JvmtiTagHashmap : public CHeapObj<mtInternal> {
   1.114 + private:
   1.115 +  friend class JvmtiTagMap;
   1.116 +
   1.117 +  enum {
   1.118 +    small_trace_threshold  = 10000,                  // threshold for tracing
   1.119 +    medium_trace_threshold = 100000,
   1.120 +    large_trace_threshold  = 1000000,
   1.121 +    initial_trace_threshold = small_trace_threshold
   1.122 +  };
   1.123 +
   1.124 +  static int _sizes[];                  // array of possible hashmap sizes
   1.125 +  int _size;                            // actual size of the table
   1.126 +  int _size_index;                      // index into size table
   1.127 +
   1.128 +  int _entry_count;                     // number of entries in the hashmap
   1.129 +
   1.130 +  float _load_factor;                   // load factor as a % of the size
   1.131 +  int _resize_threshold;                // computed threshold to trigger resizing.
   1.132 +  bool _resizing_enabled;               // indicates if hashmap can resize
   1.133 +
   1.134 +  int _trace_threshold;                 // threshold for trace messages
   1.135 +
   1.136 +  JvmtiTagHashmapEntry** _table;        // the table of entries.
   1.137 +
   1.138 +  // private accessors
   1.139 +  int resize_threshold() const                  { return _resize_threshold; }
   1.140 +  int trace_threshold() const                   { return _trace_threshold; }
   1.141 +
   1.142 +  // initialize the hashmap
   1.143 +  void init(int size_index=0, float load_factor=4.0f) {
   1.144 +    int initial_size =  _sizes[size_index];
   1.145 +    _size_index = size_index;
   1.146 +    _size = initial_size;
   1.147 +    _entry_count = 0;
   1.148 +    if (TraceJVMTIObjectTagging) {
   1.149 +      _trace_threshold = initial_trace_threshold;
   1.150 +    } else {
   1.151 +      _trace_threshold = -1;
   1.152 +    }
   1.153 +    _load_factor = load_factor;
   1.154 +    _resize_threshold = (int)(_load_factor * _size);
   1.155 +    _resizing_enabled = true;
   1.156 +    size_t s = initial_size * sizeof(JvmtiTagHashmapEntry*);
   1.157 +    _table = (JvmtiTagHashmapEntry**)os::malloc(s, mtInternal);
   1.158 +    if (_table == NULL) {
   1.159 +      vm_exit_out_of_memory(s, OOM_MALLOC_ERROR,
   1.160 +        "unable to allocate initial hashtable for jvmti object tags");
   1.161 +    }
   1.162 +    for (int i=0; i<initial_size; i++) {
   1.163 +      _table[i] = NULL;
   1.164 +    }
   1.165 +  }
   1.166 +
   1.167 +  // hash a given key (oop) with the specified size
   1.168 +  static unsigned int hash(oop key, int size) {
   1.169 +    // shift right to get better distribution (as these bits will be zero
   1.170 +    // with aligned addresses)
   1.171 +    unsigned int addr = (unsigned int)(cast_from_oop<intptr_t>(key));
   1.172 +#ifdef _LP64
   1.173 +    return (addr >> 3) % size;
   1.174 +#else
   1.175 +    return (addr >> 2) % size;
   1.176 +#endif
   1.177 +  }
   1.178 +
   1.179 +  // hash a given key (oop)
   1.180 +  unsigned int hash(oop key) {
   1.181 +    return hash(key, _size);
   1.182 +  }
   1.183 +
   1.184 +  // resize the hashmap - allocates a large table and re-hashes
   1.185 +  // all entries into the new table.
   1.186 +  void resize() {
   1.187 +    int new_size_index = _size_index+1;
   1.188 +    int new_size = _sizes[new_size_index];
   1.189 +    if (new_size < 0) {
   1.190 +      // hashmap already at maximum capacity
   1.191 +      return;
   1.192 +    }
   1.193 +
   1.194 +    // allocate new table
   1.195 +    size_t s = new_size * sizeof(JvmtiTagHashmapEntry*);
   1.196 +    JvmtiTagHashmapEntry** new_table = (JvmtiTagHashmapEntry**)os::malloc(s, mtInternal);
   1.197 +    if (new_table == NULL) {
   1.198 +      warning("unable to allocate larger hashtable for jvmti object tags");
   1.199 +      set_resizing_enabled(false);
   1.200 +      return;
   1.201 +    }
   1.202 +
   1.203 +    // initialize new table
   1.204 +    int i;
   1.205 +    for (i=0; i<new_size; i++) {
   1.206 +      new_table[i] = NULL;
   1.207 +    }
   1.208 +
   1.209 +    // rehash all entries into the new table
   1.210 +    for (i=0; i<_size; i++) {
   1.211 +      JvmtiTagHashmapEntry* entry = _table[i];
   1.212 +      while (entry != NULL) {
   1.213 +        JvmtiTagHashmapEntry* next = entry->next();
   1.214 +        oop key = entry->object();
   1.215 +        assert(key != NULL, "jni weak reference cleared!!");
   1.216 +        unsigned int h = hash(key, new_size);
   1.217 +        JvmtiTagHashmapEntry* anchor = new_table[h];
   1.218 +        if (anchor == NULL) {
   1.219 +          new_table[h] = entry;
   1.220 +          entry->set_next(NULL);
   1.221 +        } else {
   1.222 +          entry->set_next(anchor);
   1.223 +          new_table[h] = entry;
   1.224 +        }
   1.225 +        entry = next;
   1.226 +      }
   1.227 +    }
   1.228 +
   1.229 +    // free old table and update settings.
   1.230 +    os::free((void*)_table);
   1.231 +    _table = new_table;
   1.232 +    _size_index = new_size_index;
   1.233 +    _size = new_size;
   1.234 +
   1.235 +    // compute new resize threshold
   1.236 +    _resize_threshold = (int)(_load_factor * _size);
   1.237 +  }
   1.238 +
   1.239 +
   1.240 +  // internal remove function - remove an entry at a given position in the
   1.241 +  // table.
   1.242 +  inline void remove(JvmtiTagHashmapEntry* prev, int pos, JvmtiTagHashmapEntry* entry) {
   1.243 +    assert(pos >= 0 && pos < _size, "out of range");
   1.244 +    if (prev == NULL) {
   1.245 +      _table[pos] = entry->next();
   1.246 +    } else {
   1.247 +      prev->set_next(entry->next());
   1.248 +    }
   1.249 +    assert(_entry_count > 0, "checking");
   1.250 +    _entry_count--;
   1.251 +  }
   1.252 +
   1.253 +  // resizing switch
   1.254 +  bool is_resizing_enabled() const          { return _resizing_enabled; }
   1.255 +  void set_resizing_enabled(bool enable)    { _resizing_enabled = enable; }
   1.256 +
   1.257 +  // debugging
   1.258 +  void print_memory_usage();
   1.259 +  void compute_next_trace_threshold();
   1.260 +
   1.261 + public:
   1.262 +
   1.263 +  // create a JvmtiTagHashmap of a preferred size and optionally a load factor.
   1.264 +  // The preferred size is rounded down to an actual size.
   1.265 +  JvmtiTagHashmap(int size, float load_factor=0.0f) {
   1.266 +    int i=0;
   1.267 +    while (_sizes[i] < size) {
   1.268 +      if (_sizes[i] < 0) {
   1.269 +        assert(i > 0, "sanity check");
   1.270 +        i--;
   1.271 +        break;
   1.272 +      }
   1.273 +      i++;
   1.274 +    }
   1.275 +
   1.276 +    // if a load factor is specified then use it, otherwise use default
   1.277 +    if (load_factor > 0.01f) {
   1.278 +      init(i, load_factor);
   1.279 +    } else {
   1.280 +      init(i);
   1.281 +    }
   1.282 +  }
   1.283 +
   1.284 +  // create a JvmtiTagHashmap with default settings
   1.285 +  JvmtiTagHashmap() {
   1.286 +    init();
   1.287 +  }
   1.288 +
   1.289 +  // release table when JvmtiTagHashmap destroyed
   1.290 +  ~JvmtiTagHashmap() {
   1.291 +    if (_table != NULL) {
   1.292 +      os::free((void*)_table);
   1.293 +      _table = NULL;
   1.294 +    }
   1.295 +  }
   1.296 +
   1.297 +  // accessors
   1.298 +  int size() const                              { return _size; }
   1.299 +  JvmtiTagHashmapEntry** table() const          { return _table; }
   1.300 +  int entry_count() const                       { return _entry_count; }
   1.301 +
   1.302 +  // find an entry in the hashmap, returns NULL if not found.
   1.303 +  inline JvmtiTagHashmapEntry* find(oop key) {
   1.304 +    unsigned int h = hash(key);
   1.305 +    JvmtiTagHashmapEntry* entry = _table[h];
   1.306 +    while (entry != NULL) {
   1.307 +      if (entry->object() == key) {
   1.308 +         return entry;
   1.309 +      }
   1.310 +      entry = entry->next();
   1.311 +    }
   1.312 +    return NULL;
   1.313 +  }
   1.314 +
   1.315 +
   1.316 +  // add a new entry to hashmap
   1.317 +  inline void add(oop key, JvmtiTagHashmapEntry* entry) {
   1.318 +    assert(key != NULL, "checking");
   1.319 +    assert(find(key) == NULL, "duplicate detected");
   1.320 +    unsigned int h = hash(key);
   1.321 +    JvmtiTagHashmapEntry* anchor = _table[h];
   1.322 +    if (anchor == NULL) {
   1.323 +      _table[h] = entry;
   1.324 +      entry->set_next(NULL);
   1.325 +    } else {
   1.326 +      entry->set_next(anchor);
   1.327 +      _table[h] = entry;
   1.328 +    }
   1.329 +
   1.330 +    _entry_count++;
   1.331 +    if (trace_threshold() > 0 && entry_count() >= trace_threshold()) {
   1.332 +      assert(TraceJVMTIObjectTagging, "should only get here when tracing");
   1.333 +      print_memory_usage();
   1.334 +      compute_next_trace_threshold();
   1.335 +    }
   1.336 +
   1.337 +    // if the number of entries exceed the threshold then resize
   1.338 +    if (entry_count() > resize_threshold() && is_resizing_enabled()) {
   1.339 +      resize();
   1.340 +    }
   1.341 +  }
   1.342 +
   1.343 +  // remove an entry with the given key.
   1.344 +  inline JvmtiTagHashmapEntry* remove(oop key) {
   1.345 +    unsigned int h = hash(key);
   1.346 +    JvmtiTagHashmapEntry* entry = _table[h];
   1.347 +    JvmtiTagHashmapEntry* prev = NULL;
   1.348 +    while (entry != NULL) {
   1.349 +      if (key == entry->object()) {
   1.350 +        break;
   1.351 +      }
   1.352 +      prev = entry;
   1.353 +      entry = entry->next();
   1.354 +    }
   1.355 +    if (entry != NULL) {
   1.356 +      remove(prev, h, entry);
   1.357 +    }
   1.358 +    return entry;
   1.359 +  }
   1.360 +
   1.361 +  // iterate over all entries in the hashmap
   1.362 +  void entry_iterate(JvmtiTagHashmapEntryClosure* closure);
   1.363 +};
   1.364 +
   1.365 +// possible hashmap sizes - odd primes that roughly double in size.
   1.366 +// To avoid excessive resizing the odd primes from 4801-76831 and
   1.367 +// 76831-307261 have been removed. The list must be terminated by -1.
   1.368 +int JvmtiTagHashmap::_sizes[] =  { 4801, 76831, 307261, 614563, 1228891,
   1.369 +    2457733, 4915219, 9830479, 19660831, 39321619, 78643219, -1 };
   1.370 +
   1.371 +
   1.372 +// A supporting class for iterating over all entries in Hashmap
   1.373 +class JvmtiTagHashmapEntryClosure {
   1.374 + public:
   1.375 +  virtual void do_entry(JvmtiTagHashmapEntry* entry) = 0;
   1.376 +};
   1.377 +
   1.378 +
   1.379 +// iterate over all entries in the hashmap
   1.380 +void JvmtiTagHashmap::entry_iterate(JvmtiTagHashmapEntryClosure* closure) {
   1.381 +  for (int i=0; i<_size; i++) {
   1.382 +    JvmtiTagHashmapEntry* entry = _table[i];
   1.383 +    JvmtiTagHashmapEntry* prev = NULL;
   1.384 +    while (entry != NULL) {
   1.385 +      // obtain the next entry before invoking do_entry - this is
   1.386 +      // necessary because do_entry may remove the entry from the
   1.387 +      // hashmap.
   1.388 +      JvmtiTagHashmapEntry* next = entry->next();
   1.389 +      closure->do_entry(entry);
   1.390 +      entry = next;
   1.391 +     }
   1.392 +  }
   1.393 +}
   1.394 +
   1.395 +// debugging
   1.396 +void JvmtiTagHashmap::print_memory_usage() {
   1.397 +  intptr_t p = (intptr_t)this;
   1.398 +  tty->print("[JvmtiTagHashmap @ " INTPTR_FORMAT, p);
   1.399 +
   1.400 +  // table + entries in KB
   1.401 +  int hashmap_usage = (size()*sizeof(JvmtiTagHashmapEntry*) +
   1.402 +    entry_count()*sizeof(JvmtiTagHashmapEntry))/K;
   1.403 +
   1.404 +  int weak_globals_usage = (int)(JNIHandles::weak_global_handle_memory_usage()/K);
   1.405 +  tty->print_cr(", %d entries (%d KB) <JNI weak globals: %d KB>]",
   1.406 +    entry_count(), hashmap_usage, weak_globals_usage);
   1.407 +}
   1.408 +
   1.409 +// compute threshold for the next trace message
   1.410 +void JvmtiTagHashmap::compute_next_trace_threshold() {
   1.411 +  if (trace_threshold() < medium_trace_threshold) {
   1.412 +    _trace_threshold += small_trace_threshold;
   1.413 +  } else {
   1.414 +    if (trace_threshold() < large_trace_threshold) {
   1.415 +      _trace_threshold += medium_trace_threshold;
   1.416 +    } else {
   1.417 +      _trace_threshold += large_trace_threshold;
   1.418 +    }
   1.419 +  }
   1.420 +}
   1.421 +
   1.422 +// create a JvmtiTagMap
   1.423 +JvmtiTagMap::JvmtiTagMap(JvmtiEnv* env) :
   1.424 +  _env(env),
   1.425 +  _lock(Mutex::nonleaf+2, "JvmtiTagMap._lock", false),
   1.426 +  _free_entries(NULL),
   1.427 +  _free_entries_count(0)
   1.428 +{
   1.429 +  assert(JvmtiThreadState_lock->is_locked(), "sanity check");
   1.430 +  assert(((JvmtiEnvBase *)env)->tag_map() == NULL, "tag map already exists for environment");
   1.431 +
   1.432 +  _hashmap = new JvmtiTagHashmap();
   1.433 +
   1.434 +  // finally add us to the environment
   1.435 +  ((JvmtiEnvBase *)env)->set_tag_map(this);
   1.436 +}
   1.437 +
   1.438 +
   1.439 +// destroy a JvmtiTagMap
   1.440 +JvmtiTagMap::~JvmtiTagMap() {
   1.441 +
   1.442 +  // no lock acquired as we assume the enclosing environment is
   1.443 +  // also being destroryed.
   1.444 +  ((JvmtiEnvBase *)_env)->set_tag_map(NULL);
   1.445 +
   1.446 +  JvmtiTagHashmapEntry** table = _hashmap->table();
   1.447 +  for (int j = 0; j < _hashmap->size(); j++) {
   1.448 +    JvmtiTagHashmapEntry* entry = table[j];
   1.449 +    while (entry != NULL) {
   1.450 +      JvmtiTagHashmapEntry* next = entry->next();
   1.451 +      delete entry;
   1.452 +      entry = next;
   1.453 +    }
   1.454 +  }
   1.455 +
   1.456 +  // finally destroy the hashmap
   1.457 +  delete _hashmap;
   1.458 +  _hashmap = NULL;
   1.459 +
   1.460 +  // remove any entries on the free list
   1.461 +  JvmtiTagHashmapEntry* entry = _free_entries;
   1.462 +  while (entry != NULL) {
   1.463 +    JvmtiTagHashmapEntry* next = entry->next();
   1.464 +    delete entry;
   1.465 +    entry = next;
   1.466 +  }
   1.467 +  _free_entries = NULL;
   1.468 +}
   1.469 +
   1.470 +// create a hashmap entry
   1.471 +// - if there's an entry on the (per-environment) free list then this
   1.472 +// is returned. Otherwise an new entry is allocated.
   1.473 +JvmtiTagHashmapEntry* JvmtiTagMap::create_entry(oop ref, jlong tag) {
   1.474 +  assert(Thread::current()->is_VM_thread() || is_locked(), "checking");
   1.475 +  JvmtiTagHashmapEntry* entry;
   1.476 +  if (_free_entries == NULL) {
   1.477 +    entry = new JvmtiTagHashmapEntry(ref, tag);
   1.478 +  } else {
   1.479 +    assert(_free_entries_count > 0, "mismatched _free_entries_count");
   1.480 +    _free_entries_count--;
   1.481 +    entry = _free_entries;
   1.482 +    _free_entries = entry->next();
   1.483 +    entry->init(ref, tag);
   1.484 +  }
   1.485 +  return entry;
   1.486 +}
   1.487 +
   1.488 +// destroy an entry by returning it to the free list
   1.489 +void JvmtiTagMap::destroy_entry(JvmtiTagHashmapEntry* entry) {
   1.490 +  assert(SafepointSynchronize::is_at_safepoint() || is_locked(), "checking");
   1.491 +  // limit the size of the free list
   1.492 +  if (_free_entries_count >= max_free_entries) {
   1.493 +    delete entry;
   1.494 +  } else {
   1.495 +    entry->set_next(_free_entries);
   1.496 +    _free_entries = entry;
   1.497 +    _free_entries_count++;
   1.498 +  }
   1.499 +}
   1.500 +
   1.501 +// returns the tag map for the given environments. If the tag map
   1.502 +// doesn't exist then it is created.
   1.503 +JvmtiTagMap* JvmtiTagMap::tag_map_for(JvmtiEnv* env) {
   1.504 +  JvmtiTagMap* tag_map = ((JvmtiEnvBase*)env)->tag_map();
   1.505 +  if (tag_map == NULL) {
   1.506 +    MutexLocker mu(JvmtiThreadState_lock);
   1.507 +    tag_map = ((JvmtiEnvBase*)env)->tag_map();
   1.508 +    if (tag_map == NULL) {
   1.509 +      tag_map = new JvmtiTagMap(env);
   1.510 +    }
   1.511 +  } else {
   1.512 +    CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops());
   1.513 +  }
   1.514 +  return tag_map;
   1.515 +}
   1.516 +
   1.517 +// iterate over all entries in the tag map.
   1.518 +void JvmtiTagMap::entry_iterate(JvmtiTagHashmapEntryClosure* closure) {
   1.519 +  hashmap()->entry_iterate(closure);
   1.520 +}
   1.521 +
   1.522 +// returns true if the hashmaps are empty
   1.523 +bool JvmtiTagMap::is_empty() {
   1.524 +  assert(SafepointSynchronize::is_at_safepoint() || is_locked(), "checking");
   1.525 +  return hashmap()->entry_count() == 0;
   1.526 +}
   1.527 +
   1.528 +
   1.529 +// Return the tag value for an object, or 0 if the object is
   1.530 +// not tagged
   1.531 +//
   1.532 +static inline jlong tag_for(JvmtiTagMap* tag_map, oop o) {
   1.533 +  JvmtiTagHashmapEntry* entry = tag_map->hashmap()->find(o);
   1.534 +  if (entry == NULL) {
   1.535 +    return 0;
   1.536 +  } else {
   1.537 +    return entry->tag();
   1.538 +  }
   1.539 +}
   1.540 +
   1.541 +
   1.542 +// A CallbackWrapper is a support class for querying and tagging an object
   1.543 +// around a callback to a profiler. The constructor does pre-callback
   1.544 +// work to get the tag value, klass tag value, ... and the destructor
   1.545 +// does the post-callback work of tagging or untagging the object.
   1.546 +//
   1.547 +// {
   1.548 +//   CallbackWrapper wrapper(tag_map, o);
   1.549 +//
   1.550 +//   (*callback)(wrapper.klass_tag(), wrapper.obj_size(), wrapper.obj_tag_p(), ...)
   1.551 +//
   1.552 +// } // wrapper goes out of scope here which results in the destructor
   1.553 +//      checking to see if the object has been tagged, untagged, or the
   1.554 +//      tag value has changed.
   1.555 +//
   1.556 +class CallbackWrapper : public StackObj {
   1.557 + private:
   1.558 +  JvmtiTagMap* _tag_map;
   1.559 +  JvmtiTagHashmap* _hashmap;
   1.560 +  JvmtiTagHashmapEntry* _entry;
   1.561 +  oop _o;
   1.562 +  jlong _obj_size;
   1.563 +  jlong _obj_tag;
   1.564 +  jlong _klass_tag;
   1.565 +
   1.566 + protected:
   1.567 +  JvmtiTagMap* tag_map() const      { return _tag_map; }
   1.568 +
   1.569 +  // invoked post-callback to tag, untag, or update the tag of an object
   1.570 +  void inline post_callback_tag_update(oop o, JvmtiTagHashmap* hashmap,
   1.571 +                                       JvmtiTagHashmapEntry* entry, jlong obj_tag);
   1.572 + public:
   1.573 +  CallbackWrapper(JvmtiTagMap* tag_map, oop o) {
   1.574 +    assert(Thread::current()->is_VM_thread() || tag_map->is_locked(),
   1.575 +           "MT unsafe or must be VM thread");
   1.576 +
   1.577 +    // object to tag
   1.578 +    _o = o;
   1.579 +
   1.580 +    // object size
   1.581 +    _obj_size = (jlong)_o->size() * wordSize;
   1.582 +
   1.583 +    // record the context
   1.584 +    _tag_map = tag_map;
   1.585 +    _hashmap = tag_map->hashmap();
   1.586 +    _entry = _hashmap->find(_o);
   1.587 +
   1.588 +    // get object tag
   1.589 +    _obj_tag = (_entry == NULL) ? 0 : _entry->tag();
   1.590 +
   1.591 +    // get the class and the class's tag value
   1.592 +    assert(SystemDictionary::Class_klass()->oop_is_instanceMirror(), "Is not?");
   1.593 +
   1.594 +    _klass_tag = tag_for(tag_map, _o->klass()->java_mirror());
   1.595 +  }
   1.596 +
   1.597 +  ~CallbackWrapper() {
   1.598 +    post_callback_tag_update(_o, _hashmap, _entry, _obj_tag);
   1.599 +  }
   1.600 +
   1.601 +  inline jlong* obj_tag_p()                     { return &_obj_tag; }
   1.602 +  inline jlong obj_size() const                 { return _obj_size; }
   1.603 +  inline jlong obj_tag() const                  { return _obj_tag; }
   1.604 +  inline jlong klass_tag() const                { return _klass_tag; }
   1.605 +};
   1.606 +
   1.607 +
   1.608 +
   1.609 +// callback post-callback to tag, untag, or update the tag of an object
   1.610 +void inline CallbackWrapper::post_callback_tag_update(oop o,
   1.611 +                                                      JvmtiTagHashmap* hashmap,
   1.612 +                                                      JvmtiTagHashmapEntry* entry,
   1.613 +                                                      jlong obj_tag) {
   1.614 +  if (entry == NULL) {
   1.615 +    if (obj_tag != 0) {
   1.616 +      // callback has tagged the object
   1.617 +      assert(Thread::current()->is_VM_thread(), "must be VMThread");
   1.618 +      entry = tag_map()->create_entry(o, obj_tag);
   1.619 +      hashmap->add(o, entry);
   1.620 +    }
   1.621 +  } else {
   1.622 +    // object was previously tagged - the callback may have untagged
   1.623 +    // the object or changed the tag value
   1.624 +    if (obj_tag == 0) {
   1.625 +
   1.626 +      JvmtiTagHashmapEntry* entry_removed = hashmap->remove(o);
   1.627 +      assert(entry_removed == entry, "checking");
   1.628 +      tag_map()->destroy_entry(entry);
   1.629 +
   1.630 +    } else {
   1.631 +      if (obj_tag != entry->tag()) {
   1.632 +         entry->set_tag(obj_tag);
   1.633 +      }
   1.634 +    }
   1.635 +  }
   1.636 +}
   1.637 +
   1.638 +// An extended CallbackWrapper used when reporting an object reference
   1.639 +// to the agent.
   1.640 +//
   1.641 +// {
   1.642 +//   TwoOopCallbackWrapper wrapper(tag_map, referrer, o);
   1.643 +//
   1.644 +//   (*callback)(wrapper.klass_tag(),
   1.645 +//               wrapper.obj_size(),
   1.646 +//               wrapper.obj_tag_p()
   1.647 +//               wrapper.referrer_tag_p(), ...)
   1.648 +//
   1.649 +// } // wrapper goes out of scope here which results in the destructor
   1.650 +//      checking to see if the referrer object has been tagged, untagged,
   1.651 +//      or the tag value has changed.
   1.652 +//
   1.653 +class TwoOopCallbackWrapper : public CallbackWrapper {
   1.654 + private:
   1.655 +  bool _is_reference_to_self;
   1.656 +  JvmtiTagHashmap* _referrer_hashmap;
   1.657 +  JvmtiTagHashmapEntry* _referrer_entry;
   1.658 +  oop _referrer;
   1.659 +  jlong _referrer_obj_tag;
   1.660 +  jlong _referrer_klass_tag;
   1.661 +  jlong* _referrer_tag_p;
   1.662 +
   1.663 +  bool is_reference_to_self() const             { return _is_reference_to_self; }
   1.664 +
   1.665 + public:
   1.666 +  TwoOopCallbackWrapper(JvmtiTagMap* tag_map, oop referrer, oop o) :
   1.667 +    CallbackWrapper(tag_map, o)
   1.668 +  {
   1.669 +    // self reference needs to be handled in a special way
   1.670 +    _is_reference_to_self = (referrer == o);
   1.671 +
   1.672 +    if (_is_reference_to_self) {
   1.673 +      _referrer_klass_tag = klass_tag();
   1.674 +      _referrer_tag_p = obj_tag_p();
   1.675 +    } else {
   1.676 +      _referrer = referrer;
   1.677 +      // record the context
   1.678 +      _referrer_hashmap = tag_map->hashmap();
   1.679 +      _referrer_entry = _referrer_hashmap->find(_referrer);
   1.680 +
   1.681 +      // get object tag
   1.682 +      _referrer_obj_tag = (_referrer_entry == NULL) ? 0 : _referrer_entry->tag();
   1.683 +      _referrer_tag_p = &_referrer_obj_tag;
   1.684 +
   1.685 +      // get referrer class tag.
   1.686 +      _referrer_klass_tag = tag_for(tag_map, _referrer->klass()->java_mirror());
   1.687 +    }
   1.688 +  }
   1.689 +
   1.690 +  ~TwoOopCallbackWrapper() {
   1.691 +    if (!is_reference_to_self()){
   1.692 +      post_callback_tag_update(_referrer,
   1.693 +                               _referrer_hashmap,
   1.694 +                               _referrer_entry,
   1.695 +                               _referrer_obj_tag);
   1.696 +    }
   1.697 +  }
   1.698 +
   1.699 +  // address of referrer tag
   1.700 +  // (for a self reference this will return the same thing as obj_tag_p())
   1.701 +  inline jlong* referrer_tag_p()        { return _referrer_tag_p; }
   1.702 +
   1.703 +  // referrer's class tag
   1.704 +  inline jlong referrer_klass_tag()     { return _referrer_klass_tag; }
   1.705 +};
   1.706 +
   1.707 +// tag an object
   1.708 +//
   1.709 +// This function is performance critical. If many threads attempt to tag objects
   1.710 +// around the same time then it's possible that the Mutex associated with the
   1.711 +// tag map will be a hot lock.
   1.712 +void JvmtiTagMap::set_tag(jobject object, jlong tag) {
   1.713 +  MutexLocker ml(lock());
   1.714 +
   1.715 +  // resolve the object
   1.716 +  oop o = JNIHandles::resolve_non_null(object);
   1.717 +
   1.718 +  // see if the object is already tagged
   1.719 +  JvmtiTagHashmap* hashmap = _hashmap;
   1.720 +  JvmtiTagHashmapEntry* entry = hashmap->find(o);
   1.721 +
   1.722 +  // if the object is not already tagged then we tag it
   1.723 +  if (entry == NULL) {
   1.724 +    if (tag != 0) {
   1.725 +      entry = create_entry(o, tag);
   1.726 +      hashmap->add(o, entry);
   1.727 +    } else {
   1.728 +      // no-op
   1.729 +    }
   1.730 +  } else {
   1.731 +    // if the object is already tagged then we either update
   1.732 +    // the tag (if a new tag value has been provided)
   1.733 +    // or remove the object if the new tag value is 0.
   1.734 +    if (tag == 0) {
   1.735 +      hashmap->remove(o);
   1.736 +      destroy_entry(entry);
   1.737 +    } else {
   1.738 +      entry->set_tag(tag);
   1.739 +    }
   1.740 +  }
   1.741 +}
   1.742 +
   1.743 +// get the tag for an object
   1.744 +jlong JvmtiTagMap::get_tag(jobject object) {
   1.745 +  MutexLocker ml(lock());
   1.746 +
   1.747 +  // resolve the object
   1.748 +  oop o = JNIHandles::resolve_non_null(object);
   1.749 +
   1.750 +  return tag_for(this, o);
   1.751 +}
   1.752 +
   1.753 +
   1.754 +// Helper class used to describe the static or instance fields of a class.
   1.755 +// For each field it holds the field index (as defined by the JVMTI specification),
   1.756 +// the field type, and the offset.
   1.757 +
   1.758 +class ClassFieldDescriptor: public CHeapObj<mtInternal> {
   1.759 + private:
   1.760 +  int _field_index;
   1.761 +  int _field_offset;
   1.762 +  char _field_type;
   1.763 + public:
   1.764 +  ClassFieldDescriptor(int index, char type, int offset) :
   1.765 +    _field_index(index), _field_type(type), _field_offset(offset) {
   1.766 +  }
   1.767 +  int field_index()  const  { return _field_index; }
   1.768 +  char field_type()  const  { return _field_type; }
   1.769 +  int field_offset() const  { return _field_offset; }
   1.770 +};
   1.771 +
   1.772 +class ClassFieldMap: public CHeapObj<mtInternal> {
   1.773 + private:
   1.774 +  enum {
   1.775 +    initial_field_count = 5
   1.776 +  };
   1.777 +
   1.778 +  // list of field descriptors
   1.779 +  GrowableArray<ClassFieldDescriptor*>* _fields;
   1.780 +
   1.781 +  // constructor
   1.782 +  ClassFieldMap();
   1.783 +
   1.784 +  // add a field
   1.785 +  void add(int index, char type, int offset);
   1.786 +
   1.787 +  // returns the field count for the given class
   1.788 +  static int compute_field_count(instanceKlassHandle ikh);
   1.789 +
   1.790 + public:
   1.791 +  ~ClassFieldMap();
   1.792 +
   1.793 +  // access
   1.794 +  int field_count()                     { return _fields->length(); }
   1.795 +  ClassFieldDescriptor* field_at(int i) { return _fields->at(i); }
   1.796 +
   1.797 +  // functions to create maps of static or instance fields
   1.798 +  static ClassFieldMap* create_map_of_static_fields(Klass* k);
   1.799 +  static ClassFieldMap* create_map_of_instance_fields(oop obj);
   1.800 +};
   1.801 +
   1.802 +ClassFieldMap::ClassFieldMap() {
   1.803 +  _fields = new (ResourceObj::C_HEAP, mtInternal)
   1.804 +    GrowableArray<ClassFieldDescriptor*>(initial_field_count, true);
   1.805 +}
   1.806 +
   1.807 +ClassFieldMap::~ClassFieldMap() {
   1.808 +  for (int i=0; i<_fields->length(); i++) {
   1.809 +    delete _fields->at(i);
   1.810 +  }
   1.811 +  delete _fields;
   1.812 +}
   1.813 +
   1.814 +void ClassFieldMap::add(int index, char type, int offset) {
   1.815 +  ClassFieldDescriptor* field = new ClassFieldDescriptor(index, type, offset);
   1.816 +  _fields->append(field);
   1.817 +}
   1.818 +
   1.819 +// Returns a heap allocated ClassFieldMap to describe the static fields
   1.820 +// of the given class.
   1.821 +//
   1.822 +ClassFieldMap* ClassFieldMap::create_map_of_static_fields(Klass* k) {
   1.823 +  HandleMark hm;
   1.824 +  instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), k);
   1.825 +
   1.826 +  // create the field map
   1.827 +  ClassFieldMap* field_map = new ClassFieldMap();
   1.828 +
   1.829 +  FilteredFieldStream f(ikh, false, false);
   1.830 +  int max_field_index = f.field_count()-1;
   1.831 +
   1.832 +  int index = 0;
   1.833 +  for (FilteredFieldStream fld(ikh, true, true); !fld.eos(); fld.next(), index++) {
   1.834 +    // ignore instance fields
   1.835 +    if (!fld.access_flags().is_static()) {
   1.836 +      continue;
   1.837 +    }
   1.838 +    field_map->add(max_field_index - index, fld.signature()->byte_at(0), fld.offset());
   1.839 +  }
   1.840 +  return field_map;
   1.841 +}
   1.842 +
   1.843 +// Returns a heap allocated ClassFieldMap to describe the instance fields
   1.844 +// of the given class. All instance fields are included (this means public
   1.845 +// and private fields declared in superclasses and superinterfaces too).
   1.846 +//
   1.847 +ClassFieldMap* ClassFieldMap::create_map_of_instance_fields(oop obj) {
   1.848 +  HandleMark hm;
   1.849 +  instanceKlassHandle ikh = instanceKlassHandle(Thread::current(), obj->klass());
   1.850 +
   1.851 +  // create the field map
   1.852 +  ClassFieldMap* field_map = new ClassFieldMap();
   1.853 +
   1.854 +  FilteredFieldStream f(ikh, false, false);
   1.855 +
   1.856 +  int max_field_index = f.field_count()-1;
   1.857 +
   1.858 +  int index = 0;
   1.859 +  for (FilteredFieldStream fld(ikh, false, false); !fld.eos(); fld.next(), index++) {
   1.860 +    // ignore static fields
   1.861 +    if (fld.access_flags().is_static()) {
   1.862 +      continue;
   1.863 +    }
   1.864 +    field_map->add(max_field_index - index, fld.signature()->byte_at(0), fld.offset());
   1.865 +  }
   1.866 +
   1.867 +  return field_map;
   1.868 +}
   1.869 +
   1.870 +// Helper class used to cache a ClassFileMap for the instance fields of
   1.871 +// a cache. A JvmtiCachedClassFieldMap can be cached by an InstanceKlass during
   1.872 +// heap iteration and avoid creating a field map for each object in the heap
   1.873 +// (only need to create the map when the first instance of a class is encountered).
   1.874 +//
   1.875 +class JvmtiCachedClassFieldMap : public CHeapObj<mtInternal> {
   1.876 + private:
   1.877 +   enum {
   1.878 +     initial_class_count = 200
   1.879 +   };
   1.880 +  ClassFieldMap* _field_map;
   1.881 +
   1.882 +  ClassFieldMap* field_map() const          { return _field_map; }
   1.883 +
   1.884 +  JvmtiCachedClassFieldMap(ClassFieldMap* field_map);
   1.885 +  ~JvmtiCachedClassFieldMap();
   1.886 +
   1.887 +  static GrowableArray<InstanceKlass*>* _class_list;
   1.888 +  static void add_to_class_list(InstanceKlass* ik);
   1.889 +
   1.890 + public:
   1.891 +  // returns the field map for a given object (returning map cached
   1.892 +  // by InstanceKlass if possible
   1.893 +  static ClassFieldMap* get_map_of_instance_fields(oop obj);
   1.894 +
   1.895 +  // removes the field map from all instanceKlasses - should be
   1.896 +  // called before VM operation completes
   1.897 +  static void clear_cache();
   1.898 +
   1.899 +  // returns the number of ClassFieldMap cached by instanceKlasses
   1.900 +  static int cached_field_map_count();
   1.901 +};
   1.902 +
   1.903 +GrowableArray<InstanceKlass*>* JvmtiCachedClassFieldMap::_class_list;
   1.904 +
   1.905 +JvmtiCachedClassFieldMap::JvmtiCachedClassFieldMap(ClassFieldMap* field_map) {
   1.906 +  _field_map = field_map;
   1.907 +}
   1.908 +
   1.909 +JvmtiCachedClassFieldMap::~JvmtiCachedClassFieldMap() {
   1.910 +  if (_field_map != NULL) {
   1.911 +    delete _field_map;
   1.912 +  }
   1.913 +}
   1.914 +
   1.915 +// Marker class to ensure that the class file map cache is only used in a defined
   1.916 +// scope.
   1.917 +class ClassFieldMapCacheMark : public StackObj {
   1.918 + private:
   1.919 +   static bool _is_active;
   1.920 + public:
   1.921 +   ClassFieldMapCacheMark() {
   1.922 +     assert(Thread::current()->is_VM_thread(), "must be VMThread");
   1.923 +     assert(JvmtiCachedClassFieldMap::cached_field_map_count() == 0, "cache not empty");
   1.924 +     assert(!_is_active, "ClassFieldMapCacheMark cannot be nested");
   1.925 +     _is_active = true;
   1.926 +   }
   1.927 +   ~ClassFieldMapCacheMark() {
   1.928 +     JvmtiCachedClassFieldMap::clear_cache();
   1.929 +     _is_active = false;
   1.930 +   }
   1.931 +   static bool is_active() { return _is_active; }
   1.932 +};
   1.933 +
   1.934 +bool ClassFieldMapCacheMark::_is_active;
   1.935 +
   1.936 +
   1.937 +// record that the given InstanceKlass is caching a field map
   1.938 +void JvmtiCachedClassFieldMap::add_to_class_list(InstanceKlass* ik) {
   1.939 +  if (_class_list == NULL) {
   1.940 +    _class_list = new (ResourceObj::C_HEAP, mtInternal)
   1.941 +      GrowableArray<InstanceKlass*>(initial_class_count, true);
   1.942 +  }
   1.943 +  _class_list->push(ik);
   1.944 +}
   1.945 +
   1.946 +// returns the instance field map for the given object
   1.947 +// (returns field map cached by the InstanceKlass if possible)
   1.948 +ClassFieldMap* JvmtiCachedClassFieldMap::get_map_of_instance_fields(oop obj) {
   1.949 +  assert(Thread::current()->is_VM_thread(), "must be VMThread");
   1.950 +  assert(ClassFieldMapCacheMark::is_active(), "ClassFieldMapCacheMark not active");
   1.951 +
   1.952 +  Klass* k = obj->klass();
   1.953 +  InstanceKlass* ik = InstanceKlass::cast(k);
   1.954 +
   1.955 +  // return cached map if possible
   1.956 +  JvmtiCachedClassFieldMap* cached_map = ik->jvmti_cached_class_field_map();
   1.957 +  if (cached_map != NULL) {
   1.958 +    assert(cached_map->field_map() != NULL, "missing field list");
   1.959 +    return cached_map->field_map();
   1.960 +  } else {
   1.961 +    ClassFieldMap* field_map = ClassFieldMap::create_map_of_instance_fields(obj);
   1.962 +    cached_map = new JvmtiCachedClassFieldMap(field_map);
   1.963 +    ik->set_jvmti_cached_class_field_map(cached_map);
   1.964 +    add_to_class_list(ik);
   1.965 +    return field_map;
   1.966 +  }
   1.967 +}
   1.968 +
   1.969 +// remove the fields maps cached from all instanceKlasses
   1.970 +void JvmtiCachedClassFieldMap::clear_cache() {
   1.971 +  assert(Thread::current()->is_VM_thread(), "must be VMThread");
   1.972 +  if (_class_list != NULL) {
   1.973 +    for (int i = 0; i < _class_list->length(); i++) {
   1.974 +      InstanceKlass* ik = _class_list->at(i);
   1.975 +      JvmtiCachedClassFieldMap* cached_map = ik->jvmti_cached_class_field_map();
   1.976 +      assert(cached_map != NULL, "should not be NULL");
   1.977 +      ik->set_jvmti_cached_class_field_map(NULL);
   1.978 +      delete cached_map;  // deletes the encapsulated field map
   1.979 +    }
   1.980 +    delete _class_list;
   1.981 +    _class_list = NULL;
   1.982 +  }
   1.983 +}
   1.984 +
   1.985 +// returns the number of ClassFieldMap cached by instanceKlasses
   1.986 +int JvmtiCachedClassFieldMap::cached_field_map_count() {
   1.987 +  return (_class_list == NULL) ? 0 : _class_list->length();
   1.988 +}
   1.989 +
   1.990 +// helper function to indicate if an object is filtered by its tag or class tag
   1.991 +static inline bool is_filtered_by_heap_filter(jlong obj_tag,
   1.992 +                                              jlong klass_tag,
   1.993 +                                              int heap_filter) {
   1.994 +  // apply the heap filter
   1.995 +  if (obj_tag != 0) {
   1.996 +    // filter out tagged objects
   1.997 +    if (heap_filter & JVMTI_HEAP_FILTER_TAGGED) return true;
   1.998 +  } else {
   1.999 +    // filter out untagged objects
  1.1000 +    if (heap_filter & JVMTI_HEAP_FILTER_UNTAGGED) return true;
  1.1001 +  }
  1.1002 +  if (klass_tag != 0) {
  1.1003 +    // filter out objects with tagged classes
  1.1004 +    if (heap_filter & JVMTI_HEAP_FILTER_CLASS_TAGGED) return true;
  1.1005 +  } else {
  1.1006 +    // filter out objects with untagged classes.
  1.1007 +    if (heap_filter & JVMTI_HEAP_FILTER_CLASS_UNTAGGED) return true;
  1.1008 +  }
  1.1009 +  return false;
  1.1010 +}
  1.1011 +
  1.1012 +// helper function to indicate if an object is filtered by a klass filter
  1.1013 +static inline bool is_filtered_by_klass_filter(oop obj, KlassHandle klass_filter) {
  1.1014 +  if (!klass_filter.is_null()) {
  1.1015 +    if (obj->klass() != klass_filter()) {
  1.1016 +      return true;
  1.1017 +    }
  1.1018 +  }
  1.1019 +  return false;
  1.1020 +}
  1.1021 +
  1.1022 +// helper function to tell if a field is a primitive field or not
  1.1023 +static inline bool is_primitive_field_type(char type) {
  1.1024 +  return (type != 'L' && type != '[');
  1.1025 +}
  1.1026 +
  1.1027 +// helper function to copy the value from location addr to jvalue.
  1.1028 +static inline void copy_to_jvalue(jvalue *v, address addr, jvmtiPrimitiveType value_type) {
  1.1029 +  switch (value_type) {
  1.1030 +    case JVMTI_PRIMITIVE_TYPE_BOOLEAN : { v->z = *(jboolean*)addr; break; }
  1.1031 +    case JVMTI_PRIMITIVE_TYPE_BYTE    : { v->b = *(jbyte*)addr;    break; }
  1.1032 +    case JVMTI_PRIMITIVE_TYPE_CHAR    : { v->c = *(jchar*)addr;    break; }
  1.1033 +    case JVMTI_PRIMITIVE_TYPE_SHORT   : { v->s = *(jshort*)addr;   break; }
  1.1034 +    case JVMTI_PRIMITIVE_TYPE_INT     : { v->i = *(jint*)addr;     break; }
  1.1035 +    case JVMTI_PRIMITIVE_TYPE_LONG    : { v->j = *(jlong*)addr;    break; }
  1.1036 +    case JVMTI_PRIMITIVE_TYPE_FLOAT   : { v->f = *(jfloat*)addr;   break; }
  1.1037 +    case JVMTI_PRIMITIVE_TYPE_DOUBLE  : { v->d = *(jdouble*)addr;  break; }
  1.1038 +    default: ShouldNotReachHere();
  1.1039 +  }
  1.1040 +}
  1.1041 +
  1.1042 +// helper function to invoke string primitive value callback
  1.1043 +// returns visit control flags
  1.1044 +static jint invoke_string_value_callback(jvmtiStringPrimitiveValueCallback cb,
  1.1045 +                                         CallbackWrapper* wrapper,
  1.1046 +                                         oop str,
  1.1047 +                                         void* user_data)
  1.1048 +{
  1.1049 +  assert(str->klass() == SystemDictionary::String_klass(), "not a string");
  1.1050 +
  1.1051 +  // get the string value and length
  1.1052 +  // (string value may be offset from the base)
  1.1053 +  int s_len = java_lang_String::length(str);
  1.1054 +  typeArrayOop s_value = java_lang_String::value(str);
  1.1055 +  int s_offset = java_lang_String::offset(str);
  1.1056 +  jchar* value;
  1.1057 +  if (s_len > 0) {
  1.1058 +    value = s_value->char_at_addr(s_offset);
  1.1059 +  } else {
  1.1060 +    value = (jchar*) s_value->base(T_CHAR);
  1.1061 +  }
  1.1062 +
  1.1063 +  // invoke the callback
  1.1064 +  return (*cb)(wrapper->klass_tag(),
  1.1065 +               wrapper->obj_size(),
  1.1066 +               wrapper->obj_tag_p(),
  1.1067 +               value,
  1.1068 +               (jint)s_len,
  1.1069 +               user_data);
  1.1070 +}
  1.1071 +
  1.1072 +// helper function to invoke string primitive value callback
  1.1073 +// returns visit control flags
  1.1074 +static jint invoke_array_primitive_value_callback(jvmtiArrayPrimitiveValueCallback cb,
  1.1075 +                                                  CallbackWrapper* wrapper,
  1.1076 +                                                  oop obj,
  1.1077 +                                                  void* user_data)
  1.1078 +{
  1.1079 +  assert(obj->is_typeArray(), "not a primitive array");
  1.1080 +
  1.1081 +  // get base address of first element
  1.1082 +  typeArrayOop array = typeArrayOop(obj);
  1.1083 +  BasicType type = TypeArrayKlass::cast(array->klass())->element_type();
  1.1084 +  void* elements = array->base(type);
  1.1085 +
  1.1086 +  // jvmtiPrimitiveType is defined so this mapping is always correct
  1.1087 +  jvmtiPrimitiveType elem_type = (jvmtiPrimitiveType)type2char(type);
  1.1088 +
  1.1089 +  return (*cb)(wrapper->klass_tag(),
  1.1090 +               wrapper->obj_size(),
  1.1091 +               wrapper->obj_tag_p(),
  1.1092 +               (jint)array->length(),
  1.1093 +               elem_type,
  1.1094 +               elements,
  1.1095 +               user_data);
  1.1096 +}
  1.1097 +
  1.1098 +// helper function to invoke the primitive field callback for all static fields
  1.1099 +// of a given class
  1.1100 +static jint invoke_primitive_field_callback_for_static_fields
  1.1101 +  (CallbackWrapper* wrapper,
  1.1102 +   oop obj,
  1.1103 +   jvmtiPrimitiveFieldCallback cb,
  1.1104 +   void* user_data)
  1.1105 +{
  1.1106 +  // for static fields only the index will be set
  1.1107 +  static jvmtiHeapReferenceInfo reference_info = { 0 };
  1.1108 +
  1.1109 +  assert(obj->klass() == SystemDictionary::Class_klass(), "not a class");
  1.1110 +  if (java_lang_Class::is_primitive(obj)) {
  1.1111 +    return 0;
  1.1112 +  }
  1.1113 +  Klass* klass = java_lang_Class::as_Klass(obj);
  1.1114 +
  1.1115 +  // ignore classes for object and type arrays
  1.1116 +  if (!klass->oop_is_instance()) {
  1.1117 +    return 0;
  1.1118 +  }
  1.1119 +
  1.1120 +  // ignore classes which aren't linked yet
  1.1121 +  InstanceKlass* ik = InstanceKlass::cast(klass);
  1.1122 +  if (!ik->is_linked()) {
  1.1123 +    return 0;
  1.1124 +  }
  1.1125 +
  1.1126 +  // get the field map
  1.1127 +  ClassFieldMap* field_map = ClassFieldMap::create_map_of_static_fields(klass);
  1.1128 +
  1.1129 +  // invoke the callback for each static primitive field
  1.1130 +  for (int i=0; i<field_map->field_count(); i++) {
  1.1131 +    ClassFieldDescriptor* field = field_map->field_at(i);
  1.1132 +
  1.1133 +    // ignore non-primitive fields
  1.1134 +    char type = field->field_type();
  1.1135 +    if (!is_primitive_field_type(type)) {
  1.1136 +      continue;
  1.1137 +    }
  1.1138 +    // one-to-one mapping
  1.1139 +    jvmtiPrimitiveType value_type = (jvmtiPrimitiveType)type;
  1.1140 +
  1.1141 +    // get offset and field value
  1.1142 +    int offset = field->field_offset();
  1.1143 +    address addr = (address)klass->java_mirror() + offset;
  1.1144 +    jvalue value;
  1.1145 +    copy_to_jvalue(&value, addr, value_type);
  1.1146 +
  1.1147 +    // field index
  1.1148 +    reference_info.field.index = field->field_index();
  1.1149 +
  1.1150 +    // invoke the callback
  1.1151 +    jint res = (*cb)(JVMTI_HEAP_REFERENCE_STATIC_FIELD,
  1.1152 +                     &reference_info,
  1.1153 +                     wrapper->klass_tag(),
  1.1154 +                     wrapper->obj_tag_p(),
  1.1155 +                     value,
  1.1156 +                     value_type,
  1.1157 +                     user_data);
  1.1158 +    if (res & JVMTI_VISIT_ABORT) {
  1.1159 +      delete field_map;
  1.1160 +      return res;
  1.1161 +    }
  1.1162 +  }
  1.1163 +
  1.1164 +  delete field_map;
  1.1165 +  return 0;
  1.1166 +}
  1.1167 +
  1.1168 +// helper function to invoke the primitive field callback for all instance fields
  1.1169 +// of a given object
  1.1170 +static jint invoke_primitive_field_callback_for_instance_fields(
  1.1171 +  CallbackWrapper* wrapper,
  1.1172 +  oop obj,
  1.1173 +  jvmtiPrimitiveFieldCallback cb,
  1.1174 +  void* user_data)
  1.1175 +{
  1.1176 +  // for instance fields only the index will be set
  1.1177 +  static jvmtiHeapReferenceInfo reference_info = { 0 };
  1.1178 +
  1.1179 +  // get the map of the instance fields
  1.1180 +  ClassFieldMap* fields = JvmtiCachedClassFieldMap::get_map_of_instance_fields(obj);
  1.1181 +
  1.1182 +  // invoke the callback for each instance primitive field
  1.1183 +  for (int i=0; i<fields->field_count(); i++) {
  1.1184 +    ClassFieldDescriptor* field = fields->field_at(i);
  1.1185 +
  1.1186 +    // ignore non-primitive fields
  1.1187 +    char type = field->field_type();
  1.1188 +    if (!is_primitive_field_type(type)) {
  1.1189 +      continue;
  1.1190 +    }
  1.1191 +    // one-to-one mapping
  1.1192 +    jvmtiPrimitiveType value_type = (jvmtiPrimitiveType)type;
  1.1193 +
  1.1194 +    // get offset and field value
  1.1195 +    int offset = field->field_offset();
  1.1196 +    address addr = (address)obj + offset;
  1.1197 +    jvalue value;
  1.1198 +    copy_to_jvalue(&value, addr, value_type);
  1.1199 +
  1.1200 +    // field index
  1.1201 +    reference_info.field.index = field->field_index();
  1.1202 +
  1.1203 +    // invoke the callback
  1.1204 +    jint res = (*cb)(JVMTI_HEAP_REFERENCE_FIELD,
  1.1205 +                     &reference_info,
  1.1206 +                     wrapper->klass_tag(),
  1.1207 +                     wrapper->obj_tag_p(),
  1.1208 +                     value,
  1.1209 +                     value_type,
  1.1210 +                     user_data);
  1.1211 +    if (res & JVMTI_VISIT_ABORT) {
  1.1212 +      return res;
  1.1213 +    }
  1.1214 +  }
  1.1215 +  return 0;
  1.1216 +}
  1.1217 +
  1.1218 +
  1.1219 +// VM operation to iterate over all objects in the heap (both reachable
  1.1220 +// and unreachable)
  1.1221 +class VM_HeapIterateOperation: public VM_Operation {
  1.1222 + private:
  1.1223 +  ObjectClosure* _blk;
  1.1224 + public:
  1.1225 +  VM_HeapIterateOperation(ObjectClosure* blk) { _blk = blk; }
  1.1226 +
  1.1227 +  VMOp_Type type() const { return VMOp_HeapIterateOperation; }
  1.1228 +  void doit() {
  1.1229 +    // allows class files maps to be cached during iteration
  1.1230 +    ClassFieldMapCacheMark cm;
  1.1231 +
  1.1232 +    // make sure that heap is parsable (fills TLABs with filler objects)
  1.1233 +    Universe::heap()->ensure_parsability(false);  // no need to retire TLABs
  1.1234 +
  1.1235 +    // Verify heap before iteration - if the heap gets corrupted then
  1.1236 +    // JVMTI's IterateOverHeap will crash.
  1.1237 +    if (VerifyBeforeIteration) {
  1.1238 +      Universe::verify();
  1.1239 +    }
  1.1240 +
  1.1241 +    // do the iteration
  1.1242 +    // If this operation encounters a bad object when using CMS,
  1.1243 +    // consider using safe_object_iterate() which avoids perm gen
  1.1244 +    // objects that may contain bad references.
  1.1245 +    Universe::heap()->object_iterate(_blk);
  1.1246 +  }
  1.1247 +
  1.1248 +};
  1.1249 +
  1.1250 +
  1.1251 +// An ObjectClosure used to support the deprecated IterateOverHeap and
  1.1252 +// IterateOverInstancesOfClass functions
  1.1253 +class IterateOverHeapObjectClosure: public ObjectClosure {
  1.1254 + private:
  1.1255 +  JvmtiTagMap* _tag_map;
  1.1256 +  KlassHandle _klass;
  1.1257 +  jvmtiHeapObjectFilter _object_filter;
  1.1258 +  jvmtiHeapObjectCallback _heap_object_callback;
  1.1259 +  const void* _user_data;
  1.1260 +
  1.1261 +  // accessors
  1.1262 +  JvmtiTagMap* tag_map() const                    { return _tag_map; }
  1.1263 +  jvmtiHeapObjectFilter object_filter() const     { return _object_filter; }
  1.1264 +  jvmtiHeapObjectCallback object_callback() const { return _heap_object_callback; }
  1.1265 +  KlassHandle klass() const                       { return _klass; }
  1.1266 +  const void* user_data() const                   { return _user_data; }
  1.1267 +
  1.1268 +  // indicates if iteration has been aborted
  1.1269 +  bool _iteration_aborted;
  1.1270 +  bool is_iteration_aborted() const               { return _iteration_aborted; }
  1.1271 +  void set_iteration_aborted(bool aborted)        { _iteration_aborted = aborted; }
  1.1272 +
  1.1273 + public:
  1.1274 +  IterateOverHeapObjectClosure(JvmtiTagMap* tag_map,
  1.1275 +                               KlassHandle klass,
  1.1276 +                               jvmtiHeapObjectFilter object_filter,
  1.1277 +                               jvmtiHeapObjectCallback heap_object_callback,
  1.1278 +                               const void* user_data) :
  1.1279 +    _tag_map(tag_map),
  1.1280 +    _klass(klass),
  1.1281 +    _object_filter(object_filter),
  1.1282 +    _heap_object_callback(heap_object_callback),
  1.1283 +    _user_data(user_data),
  1.1284 +    _iteration_aborted(false)
  1.1285 +  {
  1.1286 +  }
  1.1287 +
  1.1288 +  void do_object(oop o);
  1.1289 +};
  1.1290 +
  1.1291 +// invoked for each object in the heap
  1.1292 +void IterateOverHeapObjectClosure::do_object(oop o) {
  1.1293 +  // check if iteration has been halted
  1.1294 +  if (is_iteration_aborted()) return;
  1.1295 +
  1.1296 +  // ignore any objects that aren't visible to profiler
  1.1297 +  if (!ServiceUtil::visible_oop(o)) return;
  1.1298 +
  1.1299 +  // instanceof check when filtering by klass
  1.1300 +  if (!klass().is_null() && !o->is_a(klass()())) {
  1.1301 +    return;
  1.1302 +  }
  1.1303 +  // prepare for the calllback
  1.1304 +  CallbackWrapper wrapper(tag_map(), o);
  1.1305 +
  1.1306 +  // if the object is tagged and we're only interested in untagged objects
  1.1307 +  // then don't invoke the callback. Similiarly, if the object is untagged
  1.1308 +  // and we're only interested in tagged objects we skip the callback.
  1.1309 +  if (wrapper.obj_tag() != 0) {
  1.1310 +    if (object_filter() == JVMTI_HEAP_OBJECT_UNTAGGED) return;
  1.1311 +  } else {
  1.1312 +    if (object_filter() == JVMTI_HEAP_OBJECT_TAGGED) return;
  1.1313 +  }
  1.1314 +
  1.1315 +  // invoke the agent's callback
  1.1316 +  jvmtiIterationControl control = (*object_callback())(wrapper.klass_tag(),
  1.1317 +                                                       wrapper.obj_size(),
  1.1318 +                                                       wrapper.obj_tag_p(),
  1.1319 +                                                       (void*)user_data());
  1.1320 +  if (control == JVMTI_ITERATION_ABORT) {
  1.1321 +    set_iteration_aborted(true);
  1.1322 +  }
  1.1323 +}
  1.1324 +
  1.1325 +// An ObjectClosure used to support the IterateThroughHeap function
  1.1326 +class IterateThroughHeapObjectClosure: public ObjectClosure {
  1.1327 + private:
  1.1328 +  JvmtiTagMap* _tag_map;
  1.1329 +  KlassHandle _klass;
  1.1330 +  int _heap_filter;
  1.1331 +  const jvmtiHeapCallbacks* _callbacks;
  1.1332 +  const void* _user_data;
  1.1333 +
  1.1334 +  // accessor functions
  1.1335 +  JvmtiTagMap* tag_map() const                     { return _tag_map; }
  1.1336 +  int heap_filter() const                          { return _heap_filter; }
  1.1337 +  const jvmtiHeapCallbacks* callbacks() const      { return _callbacks; }
  1.1338 +  KlassHandle klass() const                        { return _klass; }
  1.1339 +  const void* user_data() const                    { return _user_data; }
  1.1340 +
  1.1341 +  // indicates if the iteration has been aborted
  1.1342 +  bool _iteration_aborted;
  1.1343 +  bool is_iteration_aborted() const                { return _iteration_aborted; }
  1.1344 +
  1.1345 +  // used to check the visit control flags. If the abort flag is set
  1.1346 +  // then we set the iteration aborted flag so that the iteration completes
  1.1347 +  // without processing any further objects
  1.1348 +  bool check_flags_for_abort(jint flags) {
  1.1349 +    bool is_abort = (flags & JVMTI_VISIT_ABORT) != 0;
  1.1350 +    if (is_abort) {
  1.1351 +      _iteration_aborted = true;
  1.1352 +    }
  1.1353 +    return is_abort;
  1.1354 +  }
  1.1355 +
  1.1356 + public:
  1.1357 +  IterateThroughHeapObjectClosure(JvmtiTagMap* tag_map,
  1.1358 +                                  KlassHandle klass,
  1.1359 +                                  int heap_filter,
  1.1360 +                                  const jvmtiHeapCallbacks* heap_callbacks,
  1.1361 +                                  const void* user_data) :
  1.1362 +    _tag_map(tag_map),
  1.1363 +    _klass(klass),
  1.1364 +    _heap_filter(heap_filter),
  1.1365 +    _callbacks(heap_callbacks),
  1.1366 +    _user_data(user_data),
  1.1367 +    _iteration_aborted(false)
  1.1368 +  {
  1.1369 +  }
  1.1370 +
  1.1371 +  void do_object(oop o);
  1.1372 +};
  1.1373 +
  1.1374 +// invoked for each object in the heap
  1.1375 +void IterateThroughHeapObjectClosure::do_object(oop obj) {
  1.1376 +  // check if iteration has been halted
  1.1377 +  if (is_iteration_aborted()) return;
  1.1378 +
  1.1379 +  // ignore any objects that aren't visible to profiler
  1.1380 +  if (!ServiceUtil::visible_oop(obj)) return;
  1.1381 +
  1.1382 +  // apply class filter
  1.1383 +  if (is_filtered_by_klass_filter(obj, klass())) return;
  1.1384 +
  1.1385 +  // prepare for callback
  1.1386 +  CallbackWrapper wrapper(tag_map(), obj);
  1.1387 +
  1.1388 +  // check if filtered by the heap filter
  1.1389 +  if (is_filtered_by_heap_filter(wrapper.obj_tag(), wrapper.klass_tag(), heap_filter())) {
  1.1390 +    return;
  1.1391 +  }
  1.1392 +
  1.1393 +  // for arrays we need the length, otherwise -1
  1.1394 +  bool is_array = obj->is_array();
  1.1395 +  int len = is_array ? arrayOop(obj)->length() : -1;
  1.1396 +
  1.1397 +  // invoke the object callback (if callback is provided)
  1.1398 +  if (callbacks()->heap_iteration_callback != NULL) {
  1.1399 +    jvmtiHeapIterationCallback cb = callbacks()->heap_iteration_callback;
  1.1400 +    jint res = (*cb)(wrapper.klass_tag(),
  1.1401 +                     wrapper.obj_size(),
  1.1402 +                     wrapper.obj_tag_p(),
  1.1403 +                     (jint)len,
  1.1404 +                     (void*)user_data());
  1.1405 +    if (check_flags_for_abort(res)) return;
  1.1406 +  }
  1.1407 +
  1.1408 +  // for objects and classes we report primitive fields if callback provided
  1.1409 +  if (callbacks()->primitive_field_callback != NULL && obj->is_instance()) {
  1.1410 +    jint res;
  1.1411 +    jvmtiPrimitiveFieldCallback cb = callbacks()->primitive_field_callback;
  1.1412 +    if (obj->klass() == SystemDictionary::Class_klass()) {
  1.1413 +      res = invoke_primitive_field_callback_for_static_fields(&wrapper,
  1.1414 +                                                                    obj,
  1.1415 +                                                                    cb,
  1.1416 +                                                                    (void*)user_data());
  1.1417 +    } else {
  1.1418 +      res = invoke_primitive_field_callback_for_instance_fields(&wrapper,
  1.1419 +                                                                      obj,
  1.1420 +                                                                      cb,
  1.1421 +                                                                      (void*)user_data());
  1.1422 +    }
  1.1423 +    if (check_flags_for_abort(res)) return;
  1.1424 +  }
  1.1425 +
  1.1426 +  // string callback
  1.1427 +  if (!is_array &&
  1.1428 +      callbacks()->string_primitive_value_callback != NULL &&
  1.1429 +      obj->klass() == SystemDictionary::String_klass()) {
  1.1430 +    jint res = invoke_string_value_callback(
  1.1431 +                callbacks()->string_primitive_value_callback,
  1.1432 +                &wrapper,
  1.1433 +                obj,
  1.1434 +                (void*)user_data() );
  1.1435 +    if (check_flags_for_abort(res)) return;
  1.1436 +  }
  1.1437 +
  1.1438 +  // array callback
  1.1439 +  if (is_array &&
  1.1440 +      callbacks()->array_primitive_value_callback != NULL &&
  1.1441 +      obj->is_typeArray()) {
  1.1442 +    jint res = invoke_array_primitive_value_callback(
  1.1443 +               callbacks()->array_primitive_value_callback,
  1.1444 +               &wrapper,
  1.1445 +               obj,
  1.1446 +               (void*)user_data() );
  1.1447 +    if (check_flags_for_abort(res)) return;
  1.1448 +  }
  1.1449 +};
  1.1450 +
  1.1451 +
  1.1452 +// Deprecated function to iterate over all objects in the heap
  1.1453 +void JvmtiTagMap::iterate_over_heap(jvmtiHeapObjectFilter object_filter,
  1.1454 +                                    KlassHandle klass,
  1.1455 +                                    jvmtiHeapObjectCallback heap_object_callback,
  1.1456 +                                    const void* user_data)
  1.1457 +{
  1.1458 +  MutexLocker ml(Heap_lock);
  1.1459 +  IterateOverHeapObjectClosure blk(this,
  1.1460 +                                   klass,
  1.1461 +                                   object_filter,
  1.1462 +                                   heap_object_callback,
  1.1463 +                                   user_data);
  1.1464 +  VM_HeapIterateOperation op(&blk);
  1.1465 +  VMThread::execute(&op);
  1.1466 +}
  1.1467 +
  1.1468 +
  1.1469 +// Iterates over all objects in the heap
  1.1470 +void JvmtiTagMap::iterate_through_heap(jint heap_filter,
  1.1471 +                                       KlassHandle klass,
  1.1472 +                                       const jvmtiHeapCallbacks* callbacks,
  1.1473 +                                       const void* user_data)
  1.1474 +{
  1.1475 +  MutexLocker ml(Heap_lock);
  1.1476 +  IterateThroughHeapObjectClosure blk(this,
  1.1477 +                                      klass,
  1.1478 +                                      heap_filter,
  1.1479 +                                      callbacks,
  1.1480 +                                      user_data);
  1.1481 +  VM_HeapIterateOperation op(&blk);
  1.1482 +  VMThread::execute(&op);
  1.1483 +}
  1.1484 +
  1.1485 +// support class for get_objects_with_tags
  1.1486 +
  1.1487 +class TagObjectCollector : public JvmtiTagHashmapEntryClosure {
  1.1488 + private:
  1.1489 +  JvmtiEnv* _env;
  1.1490 +  jlong* _tags;
  1.1491 +  jint _tag_count;
  1.1492 +
  1.1493 +  GrowableArray<jobject>* _object_results;  // collected objects (JNI weak refs)
  1.1494 +  GrowableArray<uint64_t>* _tag_results;    // collected tags
  1.1495 +
  1.1496 + public:
  1.1497 +  TagObjectCollector(JvmtiEnv* env, const jlong* tags, jint tag_count) {
  1.1498 +    _env = env;
  1.1499 +    _tags = (jlong*)tags;
  1.1500 +    _tag_count = tag_count;
  1.1501 +    _object_results = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<jobject>(1,true);
  1.1502 +    _tag_results = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<uint64_t>(1,true);
  1.1503 +  }
  1.1504 +
  1.1505 +  ~TagObjectCollector() {
  1.1506 +    delete _object_results;
  1.1507 +    delete _tag_results;
  1.1508 +  }
  1.1509 +
  1.1510 +  // for each tagged object check if the tag value matches
  1.1511 +  // - if it matches then we create a JNI local reference to the object
  1.1512 +  // and record the reference and tag value.
  1.1513 +  //
  1.1514 +  void do_entry(JvmtiTagHashmapEntry* entry) {
  1.1515 +    for (int i=0; i<_tag_count; i++) {
  1.1516 +      if (_tags[i] == entry->tag()) {
  1.1517 +        oop o = entry->object();
  1.1518 +        assert(o != NULL && Universe::heap()->is_in_reserved(o), "sanity check");
  1.1519 +        jobject ref = JNIHandles::make_local(JavaThread::current(), o);
  1.1520 +        _object_results->append(ref);
  1.1521 +        _tag_results->append((uint64_t)entry->tag());
  1.1522 +      }
  1.1523 +    }
  1.1524 +  }
  1.1525 +
  1.1526 +  // return the results from the collection
  1.1527 +  //
  1.1528 +  jvmtiError result(jint* count_ptr, jobject** object_result_ptr, jlong** tag_result_ptr) {
  1.1529 +    jvmtiError error;
  1.1530 +    int count = _object_results->length();
  1.1531 +    assert(count >= 0, "sanity check");
  1.1532 +
  1.1533 +    // if object_result_ptr is not NULL then allocate the result and copy
  1.1534 +    // in the object references.
  1.1535 +    if (object_result_ptr != NULL) {
  1.1536 +      error = _env->Allocate(count * sizeof(jobject), (unsigned char**)object_result_ptr);
  1.1537 +      if (error != JVMTI_ERROR_NONE) {
  1.1538 +        return error;
  1.1539 +      }
  1.1540 +      for (int i=0; i<count; i++) {
  1.1541 +        (*object_result_ptr)[i] = _object_results->at(i);
  1.1542 +      }
  1.1543 +    }
  1.1544 +
  1.1545 +    // if tag_result_ptr is not NULL then allocate the result and copy
  1.1546 +    // in the tag values.
  1.1547 +    if (tag_result_ptr != NULL) {
  1.1548 +      error = _env->Allocate(count * sizeof(jlong), (unsigned char**)tag_result_ptr);
  1.1549 +      if (error != JVMTI_ERROR_NONE) {
  1.1550 +        if (object_result_ptr != NULL) {
  1.1551 +          _env->Deallocate((unsigned char*)object_result_ptr);
  1.1552 +        }
  1.1553 +        return error;
  1.1554 +      }
  1.1555 +      for (int i=0; i<count; i++) {
  1.1556 +        (*tag_result_ptr)[i] = (jlong)_tag_results->at(i);
  1.1557 +      }
  1.1558 +    }
  1.1559 +
  1.1560 +    *count_ptr = count;
  1.1561 +    return JVMTI_ERROR_NONE;
  1.1562 +  }
  1.1563 +};
  1.1564 +
  1.1565 +// return the list of objects with the specified tags
  1.1566 +jvmtiError JvmtiTagMap::get_objects_with_tags(const jlong* tags,
  1.1567 +  jint count, jint* count_ptr, jobject** object_result_ptr, jlong** tag_result_ptr) {
  1.1568 +
  1.1569 +  TagObjectCollector collector(env(), tags, count);
  1.1570 +  {
  1.1571 +    // iterate over all tagged objects
  1.1572 +    MutexLocker ml(lock());
  1.1573 +    entry_iterate(&collector);
  1.1574 +  }
  1.1575 +  return collector.result(count_ptr, object_result_ptr, tag_result_ptr);
  1.1576 +}
  1.1577 +
  1.1578 +
  1.1579 +// ObjectMarker is used to support the marking objects when walking the
  1.1580 +// heap.
  1.1581 +//
  1.1582 +// This implementation uses the existing mark bits in an object for
  1.1583 +// marking. Objects that are marked must later have their headers restored.
  1.1584 +// As most objects are unlocked and don't have their identity hash computed
  1.1585 +// we don't have to save their headers. Instead we save the headers that
  1.1586 +// are "interesting". Later when the headers are restored this implementation
  1.1587 +// restores all headers to their initial value and then restores the few
  1.1588 +// objects that had interesting headers.
  1.1589 +//
  1.1590 +// Future work: This implementation currently uses growable arrays to save
  1.1591 +// the oop and header of interesting objects. As an optimization we could
  1.1592 +// use the same technique as the GC and make use of the unused area
  1.1593 +// between top() and end().
  1.1594 +//
  1.1595 +
  1.1596 +// An ObjectClosure used to restore the mark bits of an object
  1.1597 +class RestoreMarksClosure : public ObjectClosure {
  1.1598 + public:
  1.1599 +  void do_object(oop o) {
  1.1600 +    if (o != NULL) {
  1.1601 +      markOop mark = o->mark();
  1.1602 +      if (mark->is_marked()) {
  1.1603 +        o->init_mark();
  1.1604 +      }
  1.1605 +    }
  1.1606 +  }
  1.1607 +};
  1.1608 +
  1.1609 +// ObjectMarker provides the mark and visited functions
  1.1610 +class ObjectMarker : AllStatic {
  1.1611 + private:
  1.1612 +  // saved headers
  1.1613 +  static GrowableArray<oop>* _saved_oop_stack;
  1.1614 +  static GrowableArray<markOop>* _saved_mark_stack;
  1.1615 +  static bool _needs_reset;                  // do we need to reset mark bits?
  1.1616 +
  1.1617 + public:
  1.1618 +  static void init();                       // initialize
  1.1619 +  static void done();                       // clean-up
  1.1620 +
  1.1621 +  static inline void mark(oop o);           // mark an object
  1.1622 +  static inline bool visited(oop o);        // check if object has been visited
  1.1623 +
  1.1624 +  static inline bool needs_reset()            { return _needs_reset; }
  1.1625 +  static inline void set_needs_reset(bool v)  { _needs_reset = v; }
  1.1626 +};
  1.1627 +
  1.1628 +GrowableArray<oop>* ObjectMarker::_saved_oop_stack = NULL;
  1.1629 +GrowableArray<markOop>* ObjectMarker::_saved_mark_stack = NULL;
  1.1630 +bool ObjectMarker::_needs_reset = true;  // need to reset mark bits by default
  1.1631 +
  1.1632 +// initialize ObjectMarker - prepares for object marking
  1.1633 +void ObjectMarker::init() {
  1.1634 +  assert(Thread::current()->is_VM_thread(), "must be VMThread");
  1.1635 +
  1.1636 +  // prepare heap for iteration
  1.1637 +  Universe::heap()->ensure_parsability(false);  // no need to retire TLABs
  1.1638 +
  1.1639 +  // create stacks for interesting headers
  1.1640 +  _saved_mark_stack = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<markOop>(4000, true);
  1.1641 +  _saved_oop_stack = new (ResourceObj::C_HEAP, mtInternal) GrowableArray<oop>(4000, true);
  1.1642 +
  1.1643 +  if (UseBiasedLocking) {
  1.1644 +    BiasedLocking::preserve_marks();
  1.1645 +  }
  1.1646 +}
  1.1647 +
  1.1648 +// Object marking is done so restore object headers
  1.1649 +void ObjectMarker::done() {
  1.1650 +  // iterate over all objects and restore the mark bits to
  1.1651 +  // their initial value
  1.1652 +  RestoreMarksClosure blk;
  1.1653 +  if (needs_reset()) {
  1.1654 +    Universe::heap()->object_iterate(&blk);
  1.1655 +  } else {
  1.1656 +    // We don't need to reset mark bits on this call, but reset the
  1.1657 +    // flag to the default for the next call.
  1.1658 +    set_needs_reset(true);
  1.1659 +  }
  1.1660 +
  1.1661 +  // now restore the interesting headers
  1.1662 +  for (int i = 0; i < _saved_oop_stack->length(); i++) {
  1.1663 +    oop o = _saved_oop_stack->at(i);
  1.1664 +    markOop mark = _saved_mark_stack->at(i);
  1.1665 +    o->set_mark(mark);
  1.1666 +  }
  1.1667 +
  1.1668 +  if (UseBiasedLocking) {
  1.1669 +    BiasedLocking::restore_marks();
  1.1670 +  }
  1.1671 +
  1.1672 +  // free the stacks
  1.1673 +  delete _saved_oop_stack;
  1.1674 +  delete _saved_mark_stack;
  1.1675 +}
  1.1676 +
  1.1677 +// mark an object
  1.1678 +inline void ObjectMarker::mark(oop o) {
  1.1679 +  assert(Universe::heap()->is_in(o), "sanity check");
  1.1680 +  assert(!o->mark()->is_marked(), "should only mark an object once");
  1.1681 +
  1.1682 +  // object's mark word
  1.1683 +  markOop mark = o->mark();
  1.1684 +
  1.1685 +  if (mark->must_be_preserved(o)) {
  1.1686 +    _saved_mark_stack->push(mark);
  1.1687 +    _saved_oop_stack->push(o);
  1.1688 +  }
  1.1689 +
  1.1690 +  // mark the object
  1.1691 +  o->set_mark(markOopDesc::prototype()->set_marked());
  1.1692 +}
  1.1693 +
  1.1694 +// return true if object is marked
  1.1695 +inline bool ObjectMarker::visited(oop o) {
  1.1696 +  return o->mark()->is_marked();
  1.1697 +}
  1.1698 +
  1.1699 +// Stack allocated class to help ensure that ObjectMarker is used
  1.1700 +// correctly. Constructor initializes ObjectMarker, destructor calls
  1.1701 +// ObjectMarker's done() function to restore object headers.
  1.1702 +class ObjectMarkerController : public StackObj {
  1.1703 + public:
  1.1704 +  ObjectMarkerController() {
  1.1705 +    ObjectMarker::init();
  1.1706 +  }
  1.1707 +  ~ObjectMarkerController() {
  1.1708 +    ObjectMarker::done();
  1.1709 +  }
  1.1710 +};
  1.1711 +
  1.1712 +
  1.1713 +// helper to map a jvmtiHeapReferenceKind to an old style jvmtiHeapRootKind
  1.1714 +// (not performance critical as only used for roots)
  1.1715 +static jvmtiHeapRootKind toJvmtiHeapRootKind(jvmtiHeapReferenceKind kind) {
  1.1716 +  switch (kind) {
  1.1717 +    case JVMTI_HEAP_REFERENCE_JNI_GLOBAL:   return JVMTI_HEAP_ROOT_JNI_GLOBAL;
  1.1718 +    case JVMTI_HEAP_REFERENCE_SYSTEM_CLASS: return JVMTI_HEAP_ROOT_SYSTEM_CLASS;
  1.1719 +    case JVMTI_HEAP_REFERENCE_MONITOR:      return JVMTI_HEAP_ROOT_MONITOR;
  1.1720 +    case JVMTI_HEAP_REFERENCE_STACK_LOCAL:  return JVMTI_HEAP_ROOT_STACK_LOCAL;
  1.1721 +    case JVMTI_HEAP_REFERENCE_JNI_LOCAL:    return JVMTI_HEAP_ROOT_JNI_LOCAL;
  1.1722 +    case JVMTI_HEAP_REFERENCE_THREAD:       return JVMTI_HEAP_ROOT_THREAD;
  1.1723 +    case JVMTI_HEAP_REFERENCE_OTHER:        return JVMTI_HEAP_ROOT_OTHER;
  1.1724 +    default: ShouldNotReachHere();          return JVMTI_HEAP_ROOT_OTHER;
  1.1725 +  }
  1.1726 +}
  1.1727 +
  1.1728 +// Base class for all heap walk contexts. The base class maintains a flag
  1.1729 +// to indicate if the context is valid or not.
  1.1730 +class HeapWalkContext VALUE_OBJ_CLASS_SPEC {
  1.1731 + private:
  1.1732 +  bool _valid;
  1.1733 + public:
  1.1734 +  HeapWalkContext(bool valid)                   { _valid = valid; }
  1.1735 +  void invalidate()                             { _valid = false; }
  1.1736 +  bool is_valid() const                         { return _valid; }
  1.1737 +};
  1.1738 +
  1.1739 +// A basic heap walk context for the deprecated heap walking functions.
  1.1740 +// The context for a basic heap walk are the callbacks and fields used by
  1.1741 +// the referrer caching scheme.
  1.1742 +class BasicHeapWalkContext: public HeapWalkContext {
  1.1743 + private:
  1.1744 +  jvmtiHeapRootCallback _heap_root_callback;
  1.1745 +  jvmtiStackReferenceCallback _stack_ref_callback;
  1.1746 +  jvmtiObjectReferenceCallback _object_ref_callback;
  1.1747 +
  1.1748 +  // used for caching
  1.1749 +  oop _last_referrer;
  1.1750 +  jlong _last_referrer_tag;
  1.1751 +
  1.1752 + public:
  1.1753 +  BasicHeapWalkContext() : HeapWalkContext(false) { }
  1.1754 +
  1.1755 +  BasicHeapWalkContext(jvmtiHeapRootCallback heap_root_callback,
  1.1756 +                       jvmtiStackReferenceCallback stack_ref_callback,
  1.1757 +                       jvmtiObjectReferenceCallback object_ref_callback) :
  1.1758 +    HeapWalkContext(true),
  1.1759 +    _heap_root_callback(heap_root_callback),
  1.1760 +    _stack_ref_callback(stack_ref_callback),
  1.1761 +    _object_ref_callback(object_ref_callback),
  1.1762 +    _last_referrer(NULL),
  1.1763 +    _last_referrer_tag(0) {
  1.1764 +  }
  1.1765 +
  1.1766 +  // accessors
  1.1767 +  jvmtiHeapRootCallback heap_root_callback() const         { return _heap_root_callback; }
  1.1768 +  jvmtiStackReferenceCallback stack_ref_callback() const   { return _stack_ref_callback; }
  1.1769 +  jvmtiObjectReferenceCallback object_ref_callback() const { return _object_ref_callback;  }
  1.1770 +
  1.1771 +  oop last_referrer() const               { return _last_referrer; }
  1.1772 +  void set_last_referrer(oop referrer)    { _last_referrer = referrer; }
  1.1773 +  jlong last_referrer_tag() const         { return _last_referrer_tag; }
  1.1774 +  void set_last_referrer_tag(jlong value) { _last_referrer_tag = value; }
  1.1775 +};
  1.1776 +
  1.1777 +// The advanced heap walk context for the FollowReferences functions.
  1.1778 +// The context is the callbacks, and the fields used for filtering.
  1.1779 +class AdvancedHeapWalkContext: public HeapWalkContext {
  1.1780 + private:
  1.1781 +  jint _heap_filter;
  1.1782 +  KlassHandle _klass_filter;
  1.1783 +  const jvmtiHeapCallbacks* _heap_callbacks;
  1.1784 +
  1.1785 + public:
  1.1786 +  AdvancedHeapWalkContext() : HeapWalkContext(false) { }
  1.1787 +
  1.1788 +  AdvancedHeapWalkContext(jint heap_filter,
  1.1789 +                           KlassHandle klass_filter,
  1.1790 +                           const jvmtiHeapCallbacks* heap_callbacks) :
  1.1791 +    HeapWalkContext(true),
  1.1792 +    _heap_filter(heap_filter),
  1.1793 +    _klass_filter(klass_filter),
  1.1794 +    _heap_callbacks(heap_callbacks) {
  1.1795 +  }
  1.1796 +
  1.1797 +  // accessors
  1.1798 +  jint heap_filter() const         { return _heap_filter; }
  1.1799 +  KlassHandle klass_filter() const { return _klass_filter; }
  1.1800 +
  1.1801 +  const jvmtiHeapReferenceCallback heap_reference_callback() const {
  1.1802 +    return _heap_callbacks->heap_reference_callback;
  1.1803 +  };
  1.1804 +  const jvmtiPrimitiveFieldCallback primitive_field_callback() const {
  1.1805 +    return _heap_callbacks->primitive_field_callback;
  1.1806 +  }
  1.1807 +  const jvmtiArrayPrimitiveValueCallback array_primitive_value_callback() const {
  1.1808 +    return _heap_callbacks->array_primitive_value_callback;
  1.1809 +  }
  1.1810 +  const jvmtiStringPrimitiveValueCallback string_primitive_value_callback() const {
  1.1811 +    return _heap_callbacks->string_primitive_value_callback;
  1.1812 +  }
  1.1813 +};
  1.1814 +
  1.1815 +// The CallbackInvoker is a class with static functions that the heap walk can call
  1.1816 +// into to invoke callbacks. It works in one of two modes. The "basic" mode is
  1.1817 +// used for the deprecated IterateOverReachableObjects functions. The "advanced"
  1.1818 +// mode is for the newer FollowReferences function which supports a lot of
  1.1819 +// additional callbacks.
  1.1820 +class CallbackInvoker : AllStatic {
  1.1821 + private:
  1.1822 +  // heap walk styles
  1.1823 +  enum { basic, advanced };
  1.1824 +  static int _heap_walk_type;
  1.1825 +  static bool is_basic_heap_walk()           { return _heap_walk_type == basic; }
  1.1826 +  static bool is_advanced_heap_walk()        { return _heap_walk_type == advanced; }
  1.1827 +
  1.1828 +  // context for basic style heap walk
  1.1829 +  static BasicHeapWalkContext _basic_context;
  1.1830 +  static BasicHeapWalkContext* basic_context() {
  1.1831 +    assert(_basic_context.is_valid(), "invalid");
  1.1832 +    return &_basic_context;
  1.1833 +  }
  1.1834 +
  1.1835 +  // context for advanced style heap walk
  1.1836 +  static AdvancedHeapWalkContext _advanced_context;
  1.1837 +  static AdvancedHeapWalkContext* advanced_context() {
  1.1838 +    assert(_advanced_context.is_valid(), "invalid");
  1.1839 +    return &_advanced_context;
  1.1840 +  }
  1.1841 +
  1.1842 +  // context needed for all heap walks
  1.1843 +  static JvmtiTagMap* _tag_map;
  1.1844 +  static const void* _user_data;
  1.1845 +  static GrowableArray<oop>* _visit_stack;
  1.1846 +
  1.1847 +  // accessors
  1.1848 +  static JvmtiTagMap* tag_map()                        { return _tag_map; }
  1.1849 +  static const void* user_data()                       { return _user_data; }
  1.1850 +  static GrowableArray<oop>* visit_stack()             { return _visit_stack; }
  1.1851 +
  1.1852 +  // if the object hasn't been visited then push it onto the visit stack
  1.1853 +  // so that it will be visited later
  1.1854 +  static inline bool check_for_visit(oop obj) {
  1.1855 +    if (!ObjectMarker::visited(obj)) visit_stack()->push(obj);
  1.1856 +    return true;
  1.1857 +  }
  1.1858 +
  1.1859 +  // invoke basic style callbacks
  1.1860 +  static inline bool invoke_basic_heap_root_callback
  1.1861 +    (jvmtiHeapRootKind root_kind, oop obj);
  1.1862 +  static inline bool invoke_basic_stack_ref_callback
  1.1863 +    (jvmtiHeapRootKind root_kind, jlong thread_tag, jint depth, jmethodID method,
  1.1864 +     int slot, oop obj);
  1.1865 +  static inline bool invoke_basic_object_reference_callback
  1.1866 +    (jvmtiObjectReferenceKind ref_kind, oop referrer, oop referree, jint index);
  1.1867 +
  1.1868 +  // invoke advanced style callbacks
  1.1869 +  static inline bool invoke_advanced_heap_root_callback
  1.1870 +    (jvmtiHeapReferenceKind ref_kind, oop obj);
  1.1871 +  static inline bool invoke_advanced_stack_ref_callback
  1.1872 +    (jvmtiHeapReferenceKind ref_kind, jlong thread_tag, jlong tid, int depth,
  1.1873 +     jmethodID method, jlocation bci, jint slot, oop obj);
  1.1874 +  static inline bool invoke_advanced_object_reference_callback
  1.1875 +    (jvmtiHeapReferenceKind ref_kind, oop referrer, oop referree, jint index);
  1.1876 +
  1.1877 +  // used to report the value of primitive fields
  1.1878 +  static inline bool report_primitive_field
  1.1879 +    (jvmtiHeapReferenceKind ref_kind, oop obj, jint index, address addr, char type);
  1.1880 +
  1.1881 + public:
  1.1882 +  // initialize for basic mode
  1.1883 +  static void initialize_for_basic_heap_walk(JvmtiTagMap* tag_map,
  1.1884 +                                             GrowableArray<oop>* visit_stack,
  1.1885 +                                             const void* user_data,
  1.1886 +                                             BasicHeapWalkContext context);
  1.1887 +
  1.1888 +  // initialize for advanced mode
  1.1889 +  static void initialize_for_advanced_heap_walk(JvmtiTagMap* tag_map,
  1.1890 +                                                GrowableArray<oop>* visit_stack,
  1.1891 +                                                const void* user_data,
  1.1892 +                                                AdvancedHeapWalkContext context);
  1.1893 +
  1.1894 +   // functions to report roots
  1.1895 +  static inline bool report_simple_root(jvmtiHeapReferenceKind kind, oop o);
  1.1896 +  static inline bool report_jni_local_root(jlong thread_tag, jlong tid, jint depth,
  1.1897 +    jmethodID m, oop o);
  1.1898 +  static inline bool report_stack_ref_root(jlong thread_tag, jlong tid, jint depth,
  1.1899 +    jmethodID method, jlocation bci, jint slot, oop o);
  1.1900 +
  1.1901 +  // functions to report references
  1.1902 +  static inline bool report_array_element_reference(oop referrer, oop referree, jint index);
  1.1903 +  static inline bool report_class_reference(oop referrer, oop referree);
  1.1904 +  static inline bool report_class_loader_reference(oop referrer, oop referree);
  1.1905 +  static inline bool report_signers_reference(oop referrer, oop referree);
  1.1906 +  static inline bool report_protection_domain_reference(oop referrer, oop referree);
  1.1907 +  static inline bool report_superclass_reference(oop referrer, oop referree);
  1.1908 +  static inline bool report_interface_reference(oop referrer, oop referree);
  1.1909 +  static inline bool report_static_field_reference(oop referrer, oop referree, jint slot);
  1.1910 +  static inline bool report_field_reference(oop referrer, oop referree, jint slot);
  1.1911 +  static inline bool report_constant_pool_reference(oop referrer, oop referree, jint index);
  1.1912 +  static inline bool report_primitive_array_values(oop array);
  1.1913 +  static inline bool report_string_value(oop str);
  1.1914 +  static inline bool report_primitive_instance_field(oop o, jint index, address value, char type);
  1.1915 +  static inline bool report_primitive_static_field(oop o, jint index, address value, char type);
  1.1916 +};
  1.1917 +
  1.1918 +// statics
  1.1919 +int CallbackInvoker::_heap_walk_type;
  1.1920 +BasicHeapWalkContext CallbackInvoker::_basic_context;
  1.1921 +AdvancedHeapWalkContext CallbackInvoker::_advanced_context;
  1.1922 +JvmtiTagMap* CallbackInvoker::_tag_map;
  1.1923 +const void* CallbackInvoker::_user_data;
  1.1924 +GrowableArray<oop>* CallbackInvoker::_visit_stack;
  1.1925 +
  1.1926 +// initialize for basic heap walk (IterateOverReachableObjects et al)
  1.1927 +void CallbackInvoker::initialize_for_basic_heap_walk(JvmtiTagMap* tag_map,
  1.1928 +                                                     GrowableArray<oop>* visit_stack,
  1.1929 +                                                     const void* user_data,
  1.1930 +                                                     BasicHeapWalkContext context) {
  1.1931 +  _tag_map = tag_map;
  1.1932 +  _visit_stack = visit_stack;
  1.1933 +  _user_data = user_data;
  1.1934 +  _basic_context = context;
  1.1935 +  _advanced_context.invalidate();       // will trigger assertion if used
  1.1936 +  _heap_walk_type = basic;
  1.1937 +}
  1.1938 +
  1.1939 +// initialize for advanced heap walk (FollowReferences)
  1.1940 +void CallbackInvoker::initialize_for_advanced_heap_walk(JvmtiTagMap* tag_map,
  1.1941 +                                                        GrowableArray<oop>* visit_stack,
  1.1942 +                                                        const void* user_data,
  1.1943 +                                                        AdvancedHeapWalkContext context) {
  1.1944 +  _tag_map = tag_map;
  1.1945 +  _visit_stack = visit_stack;
  1.1946 +  _user_data = user_data;
  1.1947 +  _advanced_context = context;
  1.1948 +  _basic_context.invalidate();      // will trigger assertion if used
  1.1949 +  _heap_walk_type = advanced;
  1.1950 +}
  1.1951 +
  1.1952 +
  1.1953 +// invoke basic style heap root callback
  1.1954 +inline bool CallbackInvoker::invoke_basic_heap_root_callback(jvmtiHeapRootKind root_kind, oop obj) {
  1.1955 +  assert(ServiceUtil::visible_oop(obj), "checking");
  1.1956 +
  1.1957 +  // if we heap roots should be reported
  1.1958 +  jvmtiHeapRootCallback cb = basic_context()->heap_root_callback();
  1.1959 +  if (cb == NULL) {
  1.1960 +    return check_for_visit(obj);
  1.1961 +  }
  1.1962 +
  1.1963 +  CallbackWrapper wrapper(tag_map(), obj);
  1.1964 +  jvmtiIterationControl control = (*cb)(root_kind,
  1.1965 +                                        wrapper.klass_tag(),
  1.1966 +                                        wrapper.obj_size(),
  1.1967 +                                        wrapper.obj_tag_p(),
  1.1968 +                                        (void*)user_data());
  1.1969 +  // push root to visit stack when following references
  1.1970 +  if (control == JVMTI_ITERATION_CONTINUE &&
  1.1971 +      basic_context()->object_ref_callback() != NULL) {
  1.1972 +    visit_stack()->push(obj);
  1.1973 +  }
  1.1974 +  return control != JVMTI_ITERATION_ABORT;
  1.1975 +}
  1.1976 +
  1.1977 +// invoke basic style stack ref callback
  1.1978 +inline bool CallbackInvoker::invoke_basic_stack_ref_callback(jvmtiHeapRootKind root_kind,
  1.1979 +                                                             jlong thread_tag,
  1.1980 +                                                             jint depth,
  1.1981 +                                                             jmethodID method,
  1.1982 +                                                             jint slot,
  1.1983 +                                                             oop obj) {
  1.1984 +  assert(ServiceUtil::visible_oop(obj), "checking");
  1.1985 +
  1.1986 +  // if we stack refs should be reported
  1.1987 +  jvmtiStackReferenceCallback cb = basic_context()->stack_ref_callback();
  1.1988 +  if (cb == NULL) {
  1.1989 +    return check_for_visit(obj);
  1.1990 +  }
  1.1991 +
  1.1992 +  CallbackWrapper wrapper(tag_map(), obj);
  1.1993 +  jvmtiIterationControl control = (*cb)(root_kind,
  1.1994 +                                        wrapper.klass_tag(),
  1.1995 +                                        wrapper.obj_size(),
  1.1996 +                                        wrapper.obj_tag_p(),
  1.1997 +                                        thread_tag,
  1.1998 +                                        depth,
  1.1999 +                                        method,
  1.2000 +                                        slot,
  1.2001 +                                        (void*)user_data());
  1.2002 +  // push root to visit stack when following references
  1.2003 +  if (control == JVMTI_ITERATION_CONTINUE &&
  1.2004 +      basic_context()->object_ref_callback() != NULL) {
  1.2005 +    visit_stack()->push(obj);
  1.2006 +  }
  1.2007 +  return control != JVMTI_ITERATION_ABORT;
  1.2008 +}
  1.2009 +
  1.2010 +// invoke basic style object reference callback
  1.2011 +inline bool CallbackInvoker::invoke_basic_object_reference_callback(jvmtiObjectReferenceKind ref_kind,
  1.2012 +                                                                    oop referrer,
  1.2013 +                                                                    oop referree,
  1.2014 +                                                                    jint index) {
  1.2015 +
  1.2016 +  assert(ServiceUtil::visible_oop(referrer), "checking");
  1.2017 +  assert(ServiceUtil::visible_oop(referree), "checking");
  1.2018 +
  1.2019 +  BasicHeapWalkContext* context = basic_context();
  1.2020 +
  1.2021 +  // callback requires the referrer's tag. If it's the same referrer
  1.2022 +  // as the last call then we use the cached value.
  1.2023 +  jlong referrer_tag;
  1.2024 +  if (referrer == context->last_referrer()) {
  1.2025 +    referrer_tag = context->last_referrer_tag();
  1.2026 +  } else {
  1.2027 +    referrer_tag = tag_for(tag_map(), referrer);
  1.2028 +  }
  1.2029 +
  1.2030 +  // do the callback
  1.2031 +  CallbackWrapper wrapper(tag_map(), referree);
  1.2032 +  jvmtiObjectReferenceCallback cb = context->object_ref_callback();
  1.2033 +  jvmtiIterationControl control = (*cb)(ref_kind,
  1.2034 +                                        wrapper.klass_tag(),
  1.2035 +                                        wrapper.obj_size(),
  1.2036 +                                        wrapper.obj_tag_p(),
  1.2037 +                                        referrer_tag,
  1.2038 +                                        index,
  1.2039 +                                        (void*)user_data());
  1.2040 +
  1.2041 +  // record referrer and referrer tag. For self-references record the
  1.2042 +  // tag value from the callback as this might differ from referrer_tag.
  1.2043 +  context->set_last_referrer(referrer);
  1.2044 +  if (referrer == referree) {
  1.2045 +    context->set_last_referrer_tag(*wrapper.obj_tag_p());
  1.2046 +  } else {
  1.2047 +    context->set_last_referrer_tag(referrer_tag);
  1.2048 +  }
  1.2049 +
  1.2050 +  if (control == JVMTI_ITERATION_CONTINUE) {
  1.2051 +    return check_for_visit(referree);
  1.2052 +  } else {
  1.2053 +    return control != JVMTI_ITERATION_ABORT;
  1.2054 +  }
  1.2055 +}
  1.2056 +
  1.2057 +// invoke advanced style heap root callback
  1.2058 +inline bool CallbackInvoker::invoke_advanced_heap_root_callback(jvmtiHeapReferenceKind ref_kind,
  1.2059 +                                                                oop obj) {
  1.2060 +  assert(ServiceUtil::visible_oop(obj), "checking");
  1.2061 +
  1.2062 +  AdvancedHeapWalkContext* context = advanced_context();
  1.2063 +
  1.2064 +  // check that callback is provided
  1.2065 +  jvmtiHeapReferenceCallback cb = context->heap_reference_callback();
  1.2066 +  if (cb == NULL) {
  1.2067 +    return check_for_visit(obj);
  1.2068 +  }
  1.2069 +
  1.2070 +  // apply class filter
  1.2071 +  if (is_filtered_by_klass_filter(obj, context->klass_filter())) {
  1.2072 +    return check_for_visit(obj);
  1.2073 +  }
  1.2074 +
  1.2075 +  // setup the callback wrapper
  1.2076 +  CallbackWrapper wrapper(tag_map(), obj);
  1.2077 +
  1.2078 +  // apply tag filter
  1.2079 +  if (is_filtered_by_heap_filter(wrapper.obj_tag(),
  1.2080 +                                 wrapper.klass_tag(),
  1.2081 +                                 context->heap_filter())) {
  1.2082 +    return check_for_visit(obj);
  1.2083 +  }
  1.2084 +
  1.2085 +  // for arrays we need the length, otherwise -1
  1.2086 +  jint len = (jint)(obj->is_array() ? arrayOop(obj)->length() : -1);
  1.2087 +
  1.2088 +  // invoke the callback
  1.2089 +  jint res  = (*cb)(ref_kind,
  1.2090 +                    NULL, // referrer info
  1.2091 +                    wrapper.klass_tag(),
  1.2092 +                    0,    // referrer_class_tag is 0 for heap root
  1.2093 +                    wrapper.obj_size(),
  1.2094 +                    wrapper.obj_tag_p(),
  1.2095 +                    NULL, // referrer_tag_p
  1.2096 +                    len,
  1.2097 +                    (void*)user_data());
  1.2098 +  if (res & JVMTI_VISIT_ABORT) {
  1.2099 +    return false;// referrer class tag
  1.2100 +  }
  1.2101 +  if (res & JVMTI_VISIT_OBJECTS) {
  1.2102 +    check_for_visit(obj);
  1.2103 +  }
  1.2104 +  return true;
  1.2105 +}
  1.2106 +
  1.2107 +// report a reference from a thread stack to an object
  1.2108 +inline bool CallbackInvoker::invoke_advanced_stack_ref_callback(jvmtiHeapReferenceKind ref_kind,
  1.2109 +                                                                jlong thread_tag,
  1.2110 +                                                                jlong tid,
  1.2111 +                                                                int depth,
  1.2112 +                                                                jmethodID method,
  1.2113 +                                                                jlocation bci,
  1.2114 +                                                                jint slot,
  1.2115 +                                                                oop obj) {
  1.2116 +  assert(ServiceUtil::visible_oop(obj), "checking");
  1.2117 +
  1.2118 +  AdvancedHeapWalkContext* context = advanced_context();
  1.2119 +
  1.2120 +  // check that callback is provider
  1.2121 +  jvmtiHeapReferenceCallback cb = context->heap_reference_callback();
  1.2122 +  if (cb == NULL) {
  1.2123 +    return check_for_visit(obj);
  1.2124 +  }
  1.2125 +
  1.2126 +  // apply class filter
  1.2127 +  if (is_filtered_by_klass_filter(obj, context->klass_filter())) {
  1.2128 +    return check_for_visit(obj);
  1.2129 +  }
  1.2130 +
  1.2131 +  // setup the callback wrapper
  1.2132 +  CallbackWrapper wrapper(tag_map(), obj);
  1.2133 +
  1.2134 +  // apply tag filter
  1.2135 +  if (is_filtered_by_heap_filter(wrapper.obj_tag(),
  1.2136 +                                 wrapper.klass_tag(),
  1.2137 +                                 context->heap_filter())) {
  1.2138 +    return check_for_visit(obj);
  1.2139 +  }
  1.2140 +
  1.2141 +  // setup the referrer info
  1.2142 +  jvmtiHeapReferenceInfo reference_info;
  1.2143 +  reference_info.stack_local.thread_tag = thread_tag;
  1.2144 +  reference_info.stack_local.thread_id = tid;
  1.2145 +  reference_info.stack_local.depth = depth;
  1.2146 +  reference_info.stack_local.method = method;
  1.2147 +  reference_info.stack_local.location = bci;
  1.2148 +  reference_info.stack_local.slot = slot;
  1.2149 +
  1.2150 +  // for arrays we need the length, otherwise -1
  1.2151 +  jint len = (jint)(obj->is_array() ? arrayOop(obj)->length() : -1);
  1.2152 +
  1.2153 +  // call into the agent
  1.2154 +  int res = (*cb)(ref_kind,
  1.2155 +                  &reference_info,
  1.2156 +                  wrapper.klass_tag(),
  1.2157 +                  0,    // referrer_class_tag is 0 for heap root (stack)
  1.2158 +                  wrapper.obj_size(),
  1.2159 +                  wrapper.obj_tag_p(),
  1.2160 +                  NULL, // referrer_tag is 0 for root
  1.2161 +                  len,
  1.2162 +                  (void*)user_data());
  1.2163 +
  1.2164 +  if (res & JVMTI_VISIT_ABORT) {
  1.2165 +    return false;
  1.2166 +  }
  1.2167 +  if (res & JVMTI_VISIT_OBJECTS) {
  1.2168 +    check_for_visit(obj);
  1.2169 +  }
  1.2170 +  return true;
  1.2171 +}
  1.2172 +
  1.2173 +// This mask is used to pass reference_info to a jvmtiHeapReferenceCallback
  1.2174 +// only for ref_kinds defined by the JVM TI spec. Otherwise, NULL is passed.
  1.2175 +#define REF_INFO_MASK  ((1 << JVMTI_HEAP_REFERENCE_FIELD)         \
  1.2176 +                      | (1 << JVMTI_HEAP_REFERENCE_STATIC_FIELD)  \
  1.2177 +                      | (1 << JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT) \
  1.2178 +                      | (1 << JVMTI_HEAP_REFERENCE_CONSTANT_POOL) \
  1.2179 +                      | (1 << JVMTI_HEAP_REFERENCE_STACK_LOCAL)   \
  1.2180 +                      | (1 << JVMTI_HEAP_REFERENCE_JNI_LOCAL))
  1.2181 +
  1.2182 +// invoke the object reference callback to report a reference
  1.2183 +inline bool CallbackInvoker::invoke_advanced_object_reference_callback(jvmtiHeapReferenceKind ref_kind,
  1.2184 +                                                                       oop referrer,
  1.2185 +                                                                       oop obj,
  1.2186 +                                                                       jint index)
  1.2187 +{
  1.2188 +  // field index is only valid field in reference_info
  1.2189 +  static jvmtiHeapReferenceInfo reference_info = { 0 };
  1.2190 +
  1.2191 +  assert(ServiceUtil::visible_oop(referrer), "checking");
  1.2192 +  assert(ServiceUtil::visible_oop(obj), "checking");
  1.2193 +
  1.2194 +  AdvancedHeapWalkContext* context = advanced_context();
  1.2195 +
  1.2196 +  // check that callback is provider
  1.2197 +  jvmtiHeapReferenceCallback cb = context->heap_reference_callback();
  1.2198 +  if (cb == NULL) {
  1.2199 +    return check_for_visit(obj);
  1.2200 +  }
  1.2201 +
  1.2202 +  // apply class filter
  1.2203 +  if (is_filtered_by_klass_filter(obj, context->klass_filter())) {
  1.2204 +    return check_for_visit(obj);
  1.2205 +  }
  1.2206 +
  1.2207 +  // setup the callback wrapper
  1.2208 +  TwoOopCallbackWrapper wrapper(tag_map(), referrer, obj);
  1.2209 +
  1.2210 +  // apply tag filter
  1.2211 +  if (is_filtered_by_heap_filter(wrapper.obj_tag(),
  1.2212 +                                 wrapper.klass_tag(),
  1.2213 +                                 context->heap_filter())) {
  1.2214 +    return check_for_visit(obj);
  1.2215 +  }
  1.2216 +
  1.2217 +  // field index is only valid field in reference_info
  1.2218 +  reference_info.field.index = index;
  1.2219 +
  1.2220 +  // for arrays we need the length, otherwise -1
  1.2221 +  jint len = (jint)(obj->is_array() ? arrayOop(obj)->length() : -1);
  1.2222 +
  1.2223 +  // invoke the callback
  1.2224 +  int res = (*cb)(ref_kind,
  1.2225 +                  (REF_INFO_MASK & (1 << ref_kind)) ? &reference_info : NULL,
  1.2226 +                  wrapper.klass_tag(),
  1.2227 +                  wrapper.referrer_klass_tag(),
  1.2228 +                  wrapper.obj_size(),
  1.2229 +                  wrapper.obj_tag_p(),
  1.2230 +                  wrapper.referrer_tag_p(),
  1.2231 +                  len,
  1.2232 +                  (void*)user_data());
  1.2233 +
  1.2234 +  if (res & JVMTI_VISIT_ABORT) {
  1.2235 +    return false;
  1.2236 +  }
  1.2237 +  if (res & JVMTI_VISIT_OBJECTS) {
  1.2238 +    check_for_visit(obj);
  1.2239 +  }
  1.2240 +  return true;
  1.2241 +}
  1.2242 +
  1.2243 +// report a "simple root"
  1.2244 +inline bool CallbackInvoker::report_simple_root(jvmtiHeapReferenceKind kind, oop obj) {
  1.2245 +  assert(kind != JVMTI_HEAP_REFERENCE_STACK_LOCAL &&
  1.2246 +         kind != JVMTI_HEAP_REFERENCE_JNI_LOCAL, "not a simple root");
  1.2247 +  assert(ServiceUtil::visible_oop(obj), "checking");
  1.2248 +
  1.2249 +  if (is_basic_heap_walk()) {
  1.2250 +    // map to old style root kind
  1.2251 +    jvmtiHeapRootKind root_kind = toJvmtiHeapRootKind(kind);
  1.2252 +    return invoke_basic_heap_root_callback(root_kind, obj);
  1.2253 +  } else {
  1.2254 +    assert(is_advanced_heap_walk(), "wrong heap walk type");
  1.2255 +    return invoke_advanced_heap_root_callback(kind, obj);
  1.2256 +  }
  1.2257 +}
  1.2258 +
  1.2259 +
  1.2260 +// invoke the primitive array values
  1.2261 +inline bool CallbackInvoker::report_primitive_array_values(oop obj) {
  1.2262 +  assert(obj->is_typeArray(), "not a primitive array");
  1.2263 +
  1.2264 +  AdvancedHeapWalkContext* context = advanced_context();
  1.2265 +  assert(context->array_primitive_value_callback() != NULL, "no callback");
  1.2266 +
  1.2267 +  // apply class filter
  1.2268 +  if (is_filtered_by_klass_filter(obj, context->klass_filter())) {
  1.2269 +    return true;
  1.2270 +  }
  1.2271 +
  1.2272 +  CallbackWrapper wrapper(tag_map(), obj);
  1.2273 +
  1.2274 +  // apply tag filter
  1.2275 +  if (is_filtered_by_heap_filter(wrapper.obj_tag(),
  1.2276 +                                 wrapper.klass_tag(),
  1.2277 +                                 context->heap_filter())) {
  1.2278 +    return true;
  1.2279 +  }
  1.2280 +
  1.2281 +  // invoke the callback
  1.2282 +  int res = invoke_array_primitive_value_callback(context->array_primitive_value_callback(),
  1.2283 +                                                  &wrapper,
  1.2284 +                                                  obj,
  1.2285 +                                                  (void*)user_data());
  1.2286 +  return (!(res & JVMTI_VISIT_ABORT));
  1.2287 +}
  1.2288 +
  1.2289 +// invoke the string value callback
  1.2290 +inline bool CallbackInvoker::report_string_value(oop str) {
  1.2291 +  assert(str->klass() == SystemDictionary::String_klass(), "not a string");
  1.2292 +
  1.2293 +  AdvancedHeapWalkContext* context = advanced_context();
  1.2294 +  assert(context->string_primitive_value_callback() != NULL, "no callback");
  1.2295 +
  1.2296 +  // apply class filter
  1.2297 +  if (is_filtered_by_klass_filter(str, context->klass_filter())) {
  1.2298 +    return true;
  1.2299 +  }
  1.2300 +
  1.2301 +  CallbackWrapper wrapper(tag_map(), str);
  1.2302 +
  1.2303 +  // apply tag filter
  1.2304 +  if (is_filtered_by_heap_filter(wrapper.obj_tag(),
  1.2305 +                                 wrapper.klass_tag(),
  1.2306 +                                 context->heap_filter())) {
  1.2307 +    return true;
  1.2308 +  }
  1.2309 +
  1.2310 +  // invoke the callback
  1.2311 +  int res = invoke_string_value_callback(context->string_primitive_value_callback(),
  1.2312 +                                         &wrapper,
  1.2313 +                                         str,
  1.2314 +                                         (void*)user_data());
  1.2315 +  return (!(res & JVMTI_VISIT_ABORT));
  1.2316 +}
  1.2317 +
  1.2318 +// invoke the primitive field callback
  1.2319 +inline bool CallbackInvoker::report_primitive_field(jvmtiHeapReferenceKind ref_kind,
  1.2320 +                                                    oop obj,
  1.2321 +                                                    jint index,
  1.2322 +                                                    address addr,
  1.2323 +                                                    char type)
  1.2324 +{
  1.2325 +  // for primitive fields only the index will be set
  1.2326 +  static jvmtiHeapReferenceInfo reference_info = { 0 };
  1.2327 +
  1.2328 +  AdvancedHeapWalkContext* context = advanced_context();
  1.2329 +  assert(context->primitive_field_callback() != NULL, "no callback");
  1.2330 +
  1.2331 +  // apply class filter
  1.2332 +  if (is_filtered_by_klass_filter(obj, context->klass_filter())) {
  1.2333 +    return true;
  1.2334 +  }
  1.2335 +
  1.2336 +  CallbackWrapper wrapper(tag_map(), obj);
  1.2337 +
  1.2338 +  // apply tag filter
  1.2339 +  if (is_filtered_by_heap_filter(wrapper.obj_tag(),
  1.2340 +                                 wrapper.klass_tag(),
  1.2341 +                                 context->heap_filter())) {
  1.2342 +    return true;
  1.2343 +  }
  1.2344 +
  1.2345 +  // the field index in the referrer
  1.2346 +  reference_info.field.index = index;
  1.2347 +
  1.2348 +  // map the type
  1.2349 +  jvmtiPrimitiveType value_type = (jvmtiPrimitiveType)type;
  1.2350 +
  1.2351 +  // setup the jvalue
  1.2352 +  jvalue value;
  1.2353 +  copy_to_jvalue(&value, addr, value_type);
  1.2354 +
  1.2355 +  jvmtiPrimitiveFieldCallback cb = context->primitive_field_callback();
  1.2356 +  int res = (*cb)(ref_kind,
  1.2357 +                  &reference_info,
  1.2358 +                  wrapper.klass_tag(),
  1.2359 +                  wrapper.obj_tag_p(),
  1.2360 +                  value,
  1.2361 +                  value_type,
  1.2362 +                  (void*)user_data());
  1.2363 +  return (!(res & JVMTI_VISIT_ABORT));
  1.2364 +}
  1.2365 +
  1.2366 +
  1.2367 +// instance field
  1.2368 +inline bool CallbackInvoker::report_primitive_instance_field(oop obj,
  1.2369 +                                                             jint index,
  1.2370 +                                                             address value,
  1.2371 +                                                             char type) {
  1.2372 +  return report_primitive_field(JVMTI_HEAP_REFERENCE_FIELD,
  1.2373 +                                obj,
  1.2374 +                                index,
  1.2375 +                                value,
  1.2376 +                                type);
  1.2377 +}
  1.2378 +
  1.2379 +// static field
  1.2380 +inline bool CallbackInvoker::report_primitive_static_field(oop obj,
  1.2381 +                                                           jint index,
  1.2382 +                                                           address value,
  1.2383 +                                                           char type) {
  1.2384 +  return report_primitive_field(JVMTI_HEAP_REFERENCE_STATIC_FIELD,
  1.2385 +                                obj,
  1.2386 +                                index,
  1.2387 +                                value,
  1.2388 +                                type);
  1.2389 +}
  1.2390 +
  1.2391 +// report a JNI local (root object) to the profiler
  1.2392 +inline bool CallbackInvoker::report_jni_local_root(jlong thread_tag, jlong tid, jint depth, jmethodID m, oop obj) {
  1.2393 +  if (is_basic_heap_walk()) {
  1.2394 +    return invoke_basic_stack_ref_callback(JVMTI_HEAP_ROOT_JNI_LOCAL,
  1.2395 +                                           thread_tag,
  1.2396 +                                           depth,
  1.2397 +                                           m,
  1.2398 +                                           -1,
  1.2399 +                                           obj);
  1.2400 +  } else {
  1.2401 +    return invoke_advanced_stack_ref_callback(JVMTI_HEAP_REFERENCE_JNI_LOCAL,
  1.2402 +                                              thread_tag, tid,
  1.2403 +                                              depth,
  1.2404 +                                              m,
  1.2405 +                                              (jlocation)-1,
  1.2406 +                                              -1,
  1.2407 +                                              obj);
  1.2408 +  }
  1.2409 +}
  1.2410 +
  1.2411 +
  1.2412 +// report a local (stack reference, root object)
  1.2413 +inline bool CallbackInvoker::report_stack_ref_root(jlong thread_tag,
  1.2414 +                                                   jlong tid,
  1.2415 +                                                   jint depth,
  1.2416 +                                                   jmethodID method,
  1.2417 +                                                   jlocation bci,
  1.2418 +                                                   jint slot,
  1.2419 +                                                   oop obj) {
  1.2420 +  if (is_basic_heap_walk()) {
  1.2421 +    return invoke_basic_stack_ref_callback(JVMTI_HEAP_ROOT_STACK_LOCAL,
  1.2422 +                                           thread_tag,
  1.2423 +                                           depth,
  1.2424 +                                           method,
  1.2425 +                                           slot,
  1.2426 +                                           obj);
  1.2427 +  } else {
  1.2428 +    return invoke_advanced_stack_ref_callback(JVMTI_HEAP_REFERENCE_STACK_LOCAL,
  1.2429 +                                              thread_tag,
  1.2430 +                                              tid,
  1.2431 +                                              depth,
  1.2432 +                                              method,
  1.2433 +                                              bci,
  1.2434 +                                              slot,
  1.2435 +                                              obj);
  1.2436 +  }
  1.2437 +}
  1.2438 +
  1.2439 +// report an object referencing a class.
  1.2440 +inline bool CallbackInvoker::report_class_reference(oop referrer, oop referree) {
  1.2441 +  if (is_basic_heap_walk()) {
  1.2442 +    return invoke_basic_object_reference_callback(JVMTI_REFERENCE_CLASS, referrer, referree, -1);
  1.2443 +  } else {
  1.2444 +    return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_CLASS, referrer, referree, -1);
  1.2445 +  }
  1.2446 +}
  1.2447 +
  1.2448 +// report a class referencing its class loader.
  1.2449 +inline bool CallbackInvoker::report_class_loader_reference(oop referrer, oop referree) {
  1.2450 +  if (is_basic_heap_walk()) {
  1.2451 +    return invoke_basic_object_reference_callback(JVMTI_REFERENCE_CLASS_LOADER, referrer, referree, -1);
  1.2452 +  } else {
  1.2453 +    return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_CLASS_LOADER, referrer, referree, -1);
  1.2454 +  }
  1.2455 +}
  1.2456 +
  1.2457 +// report a class referencing its signers.
  1.2458 +inline bool CallbackInvoker::report_signers_reference(oop referrer, oop referree) {
  1.2459 +  if (is_basic_heap_walk()) {
  1.2460 +    return invoke_basic_object_reference_callback(JVMTI_REFERENCE_SIGNERS, referrer, referree, -1);
  1.2461 +  } else {
  1.2462 +    return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_SIGNERS, referrer, referree, -1);
  1.2463 +  }
  1.2464 +}
  1.2465 +
  1.2466 +// report a class referencing its protection domain..
  1.2467 +inline bool CallbackInvoker::report_protection_domain_reference(oop referrer, oop referree) {
  1.2468 +  if (is_basic_heap_walk()) {
  1.2469 +    return invoke_basic_object_reference_callback(JVMTI_REFERENCE_PROTECTION_DOMAIN, referrer, referree, -1);
  1.2470 +  } else {
  1.2471 +    return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_PROTECTION_DOMAIN, referrer, referree, -1);
  1.2472 +  }
  1.2473 +}
  1.2474 +
  1.2475 +// report a class referencing its superclass.
  1.2476 +inline bool CallbackInvoker::report_superclass_reference(oop referrer, oop referree) {
  1.2477 +  if (is_basic_heap_walk()) {
  1.2478 +    // Send this to be consistent with past implementation
  1.2479 +    return invoke_basic_object_reference_callback(JVMTI_REFERENCE_CLASS, referrer, referree, -1);
  1.2480 +  } else {
  1.2481 +    return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_SUPERCLASS, referrer, referree, -1);
  1.2482 +  }
  1.2483 +}
  1.2484 +
  1.2485 +// report a class referencing one of its interfaces.
  1.2486 +inline bool CallbackInvoker::report_interface_reference(oop referrer, oop referree) {
  1.2487 +  if (is_basic_heap_walk()) {
  1.2488 +    return invoke_basic_object_reference_callback(JVMTI_REFERENCE_INTERFACE, referrer, referree, -1);
  1.2489 +  } else {
  1.2490 +    return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_INTERFACE, referrer, referree, -1);
  1.2491 +  }
  1.2492 +}
  1.2493 +
  1.2494 +// report a class referencing one of its static fields.
  1.2495 +inline bool CallbackInvoker::report_static_field_reference(oop referrer, oop referree, jint slot) {
  1.2496 +  if (is_basic_heap_walk()) {
  1.2497 +    return invoke_basic_object_reference_callback(JVMTI_REFERENCE_STATIC_FIELD, referrer, referree, slot);
  1.2498 +  } else {
  1.2499 +    return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_STATIC_FIELD, referrer, referree, slot);
  1.2500 +  }
  1.2501 +}
  1.2502 +
  1.2503 +// report an array referencing an element object
  1.2504 +inline bool CallbackInvoker::report_array_element_reference(oop referrer, oop referree, jint index) {
  1.2505 +  if (is_basic_heap_walk()) {
  1.2506 +    return invoke_basic_object_reference_callback(JVMTI_REFERENCE_ARRAY_ELEMENT, referrer, referree, index);
  1.2507 +  } else {
  1.2508 +    return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_ARRAY_ELEMENT, referrer, referree, index);
  1.2509 +  }
  1.2510 +}
  1.2511 +
  1.2512 +// report an object referencing an instance field object
  1.2513 +inline bool CallbackInvoker::report_field_reference(oop referrer, oop referree, jint slot) {
  1.2514 +  if (is_basic_heap_walk()) {
  1.2515 +    return invoke_basic_object_reference_callback(JVMTI_REFERENCE_FIELD, referrer, referree, slot);
  1.2516 +  } else {
  1.2517 +    return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_FIELD, referrer, referree, slot);
  1.2518 +  }
  1.2519 +}
  1.2520 +
  1.2521 +// report an array referencing an element object
  1.2522 +inline bool CallbackInvoker::report_constant_pool_reference(oop referrer, oop referree, jint index) {
  1.2523 +  if (is_basic_heap_walk()) {
  1.2524 +    return invoke_basic_object_reference_callback(JVMTI_REFERENCE_CONSTANT_POOL, referrer, referree, index);
  1.2525 +  } else {
  1.2526 +    return invoke_advanced_object_reference_callback(JVMTI_HEAP_REFERENCE_CONSTANT_POOL, referrer, referree, index);
  1.2527 +  }
  1.2528 +}
  1.2529 +
  1.2530 +// A supporting closure used to process simple roots
  1.2531 +class SimpleRootsClosure : public OopClosure {
  1.2532 + private:
  1.2533 +  jvmtiHeapReferenceKind _kind;
  1.2534 +  bool _continue;
  1.2535 +
  1.2536 +  jvmtiHeapReferenceKind root_kind()    { return _kind; }
  1.2537 +
  1.2538 + public:
  1.2539 +  void set_kind(jvmtiHeapReferenceKind kind) {
  1.2540 +    _kind = kind;
  1.2541 +    _continue = true;
  1.2542 +  }
  1.2543 +
  1.2544 +  inline bool stopped() {
  1.2545 +    return !_continue;
  1.2546 +  }
  1.2547 +
  1.2548 +  void do_oop(oop* obj_p) {
  1.2549 +    // iteration has terminated
  1.2550 +    if (stopped()) {
  1.2551 +      return;
  1.2552 +    }
  1.2553 +
  1.2554 +    // ignore null or deleted handles
  1.2555 +    oop o = *obj_p;
  1.2556 +    if (o == NULL || o == JNIHandles::deleted_handle()) {
  1.2557 +      return;
  1.2558 +    }
  1.2559 +
  1.2560 +    assert(Universe::heap()->is_in_reserved(o), "should be impossible");
  1.2561 +
  1.2562 +    jvmtiHeapReferenceKind kind = root_kind();
  1.2563 +    if (kind == JVMTI_HEAP_REFERENCE_SYSTEM_CLASS) {
  1.2564 +      // SystemDictionary::always_strong_oops_do reports the application
  1.2565 +      // class loader as a root. We want this root to be reported as
  1.2566 +      // a root kind of "OTHER" rather than "SYSTEM_CLASS".
  1.2567 +      if (!o->is_instanceMirror()) {
  1.2568 +        kind = JVMTI_HEAP_REFERENCE_OTHER;
  1.2569 +      }
  1.2570 +    }
  1.2571 +
  1.2572 +    // some objects are ignored - in the case of simple
  1.2573 +    // roots it's mostly Symbol*s that we are skipping
  1.2574 +    // here.
  1.2575 +    if (!ServiceUtil::visible_oop(o)) {
  1.2576 +      return;
  1.2577 +    }
  1.2578 +
  1.2579 +    // invoke the callback
  1.2580 +    _continue = CallbackInvoker::report_simple_root(kind, o);
  1.2581 +
  1.2582 +  }
  1.2583 +  virtual void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); }
  1.2584 +};
  1.2585 +
  1.2586 +// A supporting closure used to process JNI locals
  1.2587 +class JNILocalRootsClosure : public OopClosure {
  1.2588 + private:
  1.2589 +  jlong _thread_tag;
  1.2590 +  jlong _tid;
  1.2591 +  jint _depth;
  1.2592 +  jmethodID _method;
  1.2593 +  bool _continue;
  1.2594 + public:
  1.2595 +  void set_context(jlong thread_tag, jlong tid, jint depth, jmethodID method) {
  1.2596 +    _thread_tag = thread_tag;
  1.2597 +    _tid = tid;
  1.2598 +    _depth = depth;
  1.2599 +    _method = method;
  1.2600 +    _continue = true;
  1.2601 +  }
  1.2602 +
  1.2603 +  inline bool stopped() {
  1.2604 +    return !_continue;
  1.2605 +  }
  1.2606 +
  1.2607 +  void do_oop(oop* obj_p) {
  1.2608 +    // iteration has terminated
  1.2609 +    if (stopped()) {
  1.2610 +      return;
  1.2611 +    }
  1.2612 +
  1.2613 +    // ignore null or deleted handles
  1.2614 +    oop o = *obj_p;
  1.2615 +    if (o == NULL || o == JNIHandles::deleted_handle()) {
  1.2616 +      return;
  1.2617 +    }
  1.2618 +
  1.2619 +    if (!ServiceUtil::visible_oop(o)) {
  1.2620 +      return;
  1.2621 +    }
  1.2622 +
  1.2623 +    // invoke the callback
  1.2624 +    _continue = CallbackInvoker::report_jni_local_root(_thread_tag, _tid, _depth, _method, o);
  1.2625 +  }
  1.2626 +  virtual void do_oop(narrowOop* obj_p) { ShouldNotReachHere(); }
  1.2627 +};
  1.2628 +
  1.2629 +
  1.2630 +// A VM operation to iterate over objects that are reachable from
  1.2631 +// a set of roots or an initial object.
  1.2632 +//
  1.2633 +// For VM_HeapWalkOperation the set of roots used is :-
  1.2634 +//
  1.2635 +// - All JNI global references
  1.2636 +// - All inflated monitors
  1.2637 +// - All classes loaded by the boot class loader (or all classes
  1.2638 +//     in the event that class unloading is disabled)
  1.2639 +// - All java threads
  1.2640 +// - For each java thread then all locals and JNI local references
  1.2641 +//      on the thread's execution stack
  1.2642 +// - All visible/explainable objects from Universes::oops_do
  1.2643 +//
  1.2644 +class VM_HeapWalkOperation: public VM_Operation {
  1.2645 + private:
  1.2646 +  enum {
  1.2647 +    initial_visit_stack_size = 4000
  1.2648 +  };
  1.2649 +
  1.2650 +  bool _is_advanced_heap_walk;                      // indicates FollowReferences
  1.2651 +  JvmtiTagMap* _tag_map;
  1.2652 +  Handle _initial_object;
  1.2653 +  GrowableArray<oop>* _visit_stack;                 // the visit stack
  1.2654 +
  1.2655 +  bool _collecting_heap_roots;                      // are we collecting roots
  1.2656 +  bool _following_object_refs;                      // are we following object references
  1.2657 +
  1.2658 +  bool _reporting_primitive_fields;                 // optional reporting
  1.2659 +  bool _reporting_primitive_array_values;
  1.2660 +  bool _reporting_string_values;
  1.2661 +
  1.2662 +  GrowableArray<oop>* create_visit_stack() {
  1.2663 +    return new (ResourceObj::C_HEAP, mtInternal) GrowableArray<oop>(initial_visit_stack_size, true);
  1.2664 +  }
  1.2665 +
  1.2666 +  // accessors
  1.2667 +  bool is_advanced_heap_walk() const               { return _is_advanced_heap_walk; }
  1.2668 +  JvmtiTagMap* tag_map() const                     { return _tag_map; }
  1.2669 +  Handle initial_object() const                    { return _initial_object; }
  1.2670 +
  1.2671 +  bool is_following_references() const             { return _following_object_refs; }
  1.2672 +
  1.2673 +  bool is_reporting_primitive_fields()  const      { return _reporting_primitive_fields; }
  1.2674 +  bool is_reporting_primitive_array_values() const { return _reporting_primitive_array_values; }
  1.2675 +  bool is_reporting_string_values() const          { return _reporting_string_values; }
  1.2676 +
  1.2677 +  GrowableArray<oop>* visit_stack() const          { return _visit_stack; }
  1.2678 +
  1.2679 +  // iterate over the various object types
  1.2680 +  inline bool iterate_over_array(oop o);
  1.2681 +  inline bool iterate_over_type_array(oop o);
  1.2682 +  inline bool iterate_over_class(oop o);
  1.2683 +  inline bool iterate_over_object(oop o);
  1.2684 +
  1.2685 +  // root collection
  1.2686 +  inline bool collect_simple_roots();
  1.2687 +  inline bool collect_stack_roots();
  1.2688 +  inline bool collect_stack_roots(JavaThread* java_thread, JNILocalRootsClosure* blk);
  1.2689 +
  1.2690 +  // visit an object
  1.2691 +  inline bool visit(oop o);
  1.2692 +
  1.2693 + public:
  1.2694 +  VM_HeapWalkOperation(JvmtiTagMap* tag_map,
  1.2695 +                       Handle initial_object,
  1.2696 +                       BasicHeapWalkContext callbacks,
  1.2697 +                       const void* user_data);
  1.2698 +
  1.2699 +  VM_HeapWalkOperation(JvmtiTagMap* tag_map,
  1.2700 +                       Handle initial_object,
  1.2701 +                       AdvancedHeapWalkContext callbacks,
  1.2702 +                       const void* user_data);
  1.2703 +
  1.2704 +  ~VM_HeapWalkOperation();
  1.2705 +
  1.2706 +  VMOp_Type type() const { return VMOp_HeapWalkOperation; }
  1.2707 +  void doit();
  1.2708 +};
  1.2709 +
  1.2710 +
  1.2711 +VM_HeapWalkOperation::VM_HeapWalkOperation(JvmtiTagMap* tag_map,
  1.2712 +                                           Handle initial_object,
  1.2713 +                                           BasicHeapWalkContext callbacks,
  1.2714 +                                           const void* user_data) {
  1.2715 +  _is_advanced_heap_walk = false;
  1.2716 +  _tag_map = tag_map;
  1.2717 +  _initial_object = initial_object;
  1.2718 +  _following_object_refs = (callbacks.object_ref_callback() != NULL);
  1.2719 +  _reporting_primitive_fields = false;
  1.2720 +  _reporting_primitive_array_values = false;
  1.2721 +  _reporting_string_values = false;
  1.2722 +  _visit_stack = create_visit_stack();
  1.2723 +
  1.2724 +
  1.2725 +  CallbackInvoker::initialize_for_basic_heap_walk(tag_map, _visit_stack, user_data, callbacks);
  1.2726 +}
  1.2727 +
  1.2728 +VM_HeapWalkOperation::VM_HeapWalkOperation(JvmtiTagMap* tag_map,
  1.2729 +                                           Handle initial_object,
  1.2730 +                                           AdvancedHeapWalkContext callbacks,
  1.2731 +                                           const void* user_data) {
  1.2732 +  _is_advanced_heap_walk = true;
  1.2733 +  _tag_map = tag_map;
  1.2734 +  _initial_object = initial_object;
  1.2735 +  _following_object_refs = true;
  1.2736 +  _reporting_primitive_fields = (callbacks.primitive_field_callback() != NULL);;
  1.2737 +  _reporting_primitive_array_values = (callbacks.array_primitive_value_callback() != NULL);;
  1.2738 +  _reporting_string_values = (callbacks.string_primitive_value_callback() != NULL);;
  1.2739 +  _visit_stack = create_visit_stack();
  1.2740 +
  1.2741 +  CallbackInvoker::initialize_for_advanced_heap_walk(tag_map, _visit_stack, user_data, callbacks);
  1.2742 +}
  1.2743 +
  1.2744 +VM_HeapWalkOperation::~VM_HeapWalkOperation() {
  1.2745 +  if (_following_object_refs) {
  1.2746 +    assert(_visit_stack != NULL, "checking");
  1.2747 +    delete _visit_stack;
  1.2748 +    _visit_stack = NULL;
  1.2749 +  }
  1.2750 +}
  1.2751 +
  1.2752 +// an array references its class and has a reference to
  1.2753 +// each element in the array
  1.2754 +inline bool VM_HeapWalkOperation::iterate_over_array(oop o) {
  1.2755 +  objArrayOop array = objArrayOop(o);
  1.2756 +
  1.2757 +  // array reference to its class
  1.2758 +  oop mirror = ObjArrayKlass::cast(array->klass())->java_mirror();
  1.2759 +  if (!CallbackInvoker::report_class_reference(o, mirror)) {
  1.2760 +    return false;
  1.2761 +  }
  1.2762 +
  1.2763 +  // iterate over the array and report each reference to a
  1.2764 +  // non-null element
  1.2765 +  for (int index=0; index<array->length(); index++) {
  1.2766 +    oop elem = array->obj_at(index);
  1.2767 +    if (elem == NULL) {
  1.2768 +      continue;
  1.2769 +    }
  1.2770 +
  1.2771 +    // report the array reference o[index] = elem
  1.2772 +    if (!CallbackInvoker::report_array_element_reference(o, elem, index)) {
  1.2773 +      return false;
  1.2774 +    }
  1.2775 +  }
  1.2776 +  return true;
  1.2777 +}
  1.2778 +
  1.2779 +// a type array references its class
  1.2780 +inline bool VM_HeapWalkOperation::iterate_over_type_array(oop o) {
  1.2781 +  Klass* k = o->klass();
  1.2782 +  oop mirror = k->java_mirror();
  1.2783 +  if (!CallbackInvoker::report_class_reference(o, mirror)) {
  1.2784 +    return false;
  1.2785 +  }
  1.2786 +
  1.2787 +  // report the array contents if required
  1.2788 +  if (is_reporting_primitive_array_values()) {
  1.2789 +    if (!CallbackInvoker::report_primitive_array_values(o)) {
  1.2790 +      return false;
  1.2791 +    }
  1.2792 +  }
  1.2793 +  return true;
  1.2794 +}
  1.2795 +
  1.2796 +// verify that a static oop field is in range
  1.2797 +static inline bool verify_static_oop(InstanceKlass* ik,
  1.2798 +                                     oop mirror, int offset) {
  1.2799 +  address obj_p = (address)mirror + offset;
  1.2800 +  address start = (address)InstanceMirrorKlass::start_of_static_fields(mirror);
  1.2801 +  address end = start + (java_lang_Class::static_oop_field_count(mirror) * heapOopSize);
  1.2802 +  assert(end >= start, "sanity check");
  1.2803 +
  1.2804 +  if (obj_p >= start && obj_p < end) {
  1.2805 +    return true;
  1.2806 +  } else {
  1.2807 +    return false;
  1.2808 +  }
  1.2809 +}
  1.2810 +
  1.2811 +// a class references its super class, interfaces, class loader, ...
  1.2812 +// and finally its static fields
  1.2813 +inline bool VM_HeapWalkOperation::iterate_over_class(oop java_class) {
  1.2814 +  int i;
  1.2815 +  Klass* klass = java_lang_Class::as_Klass(java_class);
  1.2816 +
  1.2817 +  if (klass->oop_is_instance()) {
  1.2818 +    InstanceKlass* ik = InstanceKlass::cast(klass);
  1.2819 +
  1.2820 +    // ignore the class if it's has been initialized yet
  1.2821 +    if (!ik->is_linked()) {
  1.2822 +      return true;
  1.2823 +    }
  1.2824 +
  1.2825 +    // get the java mirror
  1.2826 +    oop mirror = klass->java_mirror();
  1.2827 +
  1.2828 +    // super (only if something more interesting than java.lang.Object)
  1.2829 +    Klass* java_super = ik->java_super();
  1.2830 +    if (java_super != NULL && java_super != SystemDictionary::Object_klass()) {
  1.2831 +      oop super = java_super->java_mirror();
  1.2832 +      if (!CallbackInvoker::report_superclass_reference(mirror, super)) {
  1.2833 +        return false;
  1.2834 +      }
  1.2835 +    }
  1.2836 +
  1.2837 +    // class loader
  1.2838 +    oop cl = ik->class_loader();
  1.2839 +    if (cl != NULL) {
  1.2840 +      if (!CallbackInvoker::report_class_loader_reference(mirror, cl)) {
  1.2841 +        return false;
  1.2842 +      }
  1.2843 +    }
  1.2844 +
  1.2845 +    // protection domain
  1.2846 +    oop pd = ik->protection_domain();
  1.2847 +    if (pd != NULL) {
  1.2848 +      if (!CallbackInvoker::report_protection_domain_reference(mirror, pd)) {
  1.2849 +        return false;
  1.2850 +      }
  1.2851 +    }
  1.2852 +
  1.2853 +    // signers
  1.2854 +    oop signers = ik->signers();
  1.2855 +    if (signers != NULL) {
  1.2856 +      if (!CallbackInvoker::report_signers_reference(mirror, signers)) {
  1.2857 +        return false;
  1.2858 +      }
  1.2859 +    }
  1.2860 +
  1.2861 +    // references from the constant pool
  1.2862 +    {
  1.2863 +      ConstantPool* pool = ik->constants();
  1.2864 +      for (int i = 1; i < pool->length(); i++) {
  1.2865 +        constantTag tag = pool->tag_at(i).value();
  1.2866 +        if (tag.is_string() || tag.is_klass()) {
  1.2867 +          oop entry;
  1.2868 +          if (tag.is_string()) {
  1.2869 +            entry = pool->resolved_string_at(i);
  1.2870 +            // If the entry is non-null it is resolved.
  1.2871 +            if (entry == NULL) continue;
  1.2872 +          } else {
  1.2873 +            entry = pool->resolved_klass_at(i)->java_mirror();
  1.2874 +          }
  1.2875 +          if (!CallbackInvoker::report_constant_pool_reference(mirror, entry, (jint)i)) {
  1.2876 +            return false;
  1.2877 +          }
  1.2878 +        }
  1.2879 +      }
  1.2880 +    }
  1.2881 +
  1.2882 +    // interfaces
  1.2883 +    // (These will already have been reported as references from the constant pool
  1.2884 +    //  but are specified by IterateOverReachableObjects and must be reported).
  1.2885 +    Array<Klass*>* interfaces = ik->local_interfaces();
  1.2886 +    for (i = 0; i < interfaces->length(); i++) {
  1.2887 +      oop interf = ((Klass*)interfaces->at(i))->java_mirror();
  1.2888 +      if (interf == NULL) {
  1.2889 +        continue;
  1.2890 +      }
  1.2891 +      if (!CallbackInvoker::report_interface_reference(mirror, interf)) {
  1.2892 +        return false;
  1.2893 +      }
  1.2894 +    }
  1.2895 +
  1.2896 +    // iterate over the static fields
  1.2897 +
  1.2898 +    ClassFieldMap* field_map = ClassFieldMap::create_map_of_static_fields(klass);
  1.2899 +    for (i=0; i<field_map->field_count(); i++) {
  1.2900 +      ClassFieldDescriptor* field = field_map->field_at(i);
  1.2901 +      char type = field->field_type();
  1.2902 +      if (!is_primitive_field_type(type)) {
  1.2903 +        oop fld_o = mirror->obj_field(field->field_offset());
  1.2904 +        assert(verify_static_oop(ik, mirror, field->field_offset()), "sanity check");
  1.2905 +        if (fld_o != NULL) {
  1.2906 +          int slot = field->field_index();
  1.2907 +          if (!CallbackInvoker::report_static_field_reference(mirror, fld_o, slot)) {
  1.2908 +            delete field_map;
  1.2909 +            return false;
  1.2910 +          }
  1.2911 +        }
  1.2912 +      } else {
  1.2913 +         if (is_reporting_primitive_fields()) {
  1.2914 +           address addr = (address)mirror + field->field_offset();
  1.2915 +           int slot = field->field_index();
  1.2916 +           if (!CallbackInvoker::report_primitive_static_field(mirror, slot, addr, type)) {
  1.2917 +             delete field_map;
  1.2918 +             return false;
  1.2919 +          }
  1.2920 +        }
  1.2921 +      }
  1.2922 +    }
  1.2923 +    delete field_map;
  1.2924 +
  1.2925 +    return true;
  1.2926 +  }
  1.2927 +
  1.2928 +  return true;
  1.2929 +}
  1.2930 +
  1.2931 +// an object references a class and its instance fields
  1.2932 +// (static fields are ignored here as we report these as
  1.2933 +// references from the class).
  1.2934 +inline bool VM_HeapWalkOperation::iterate_over_object(oop o) {
  1.2935 +  // reference to the class
  1.2936 +  if (!CallbackInvoker::report_class_reference(o, o->klass()->java_mirror())) {
  1.2937 +    return false;
  1.2938 +  }
  1.2939 +
  1.2940 +  // iterate over instance fields
  1.2941 +  ClassFieldMap* field_map = JvmtiCachedClassFieldMap::get_map_of_instance_fields(o);
  1.2942 +  for (int i=0; i<field_map->field_count(); i++) {
  1.2943 +    ClassFieldDescriptor* field = field_map->field_at(i);
  1.2944 +    char type = field->field_type();
  1.2945 +    if (!is_primitive_field_type(type)) {
  1.2946 +      oop fld_o = o->obj_field(field->field_offset());
  1.2947 +      // ignore any objects that aren't visible to profiler
  1.2948 +      if (fld_o != NULL && ServiceUtil::visible_oop(fld_o)) {
  1.2949 +        assert(Universe::heap()->is_in_reserved(fld_o), "unsafe code should not "
  1.2950 +               "have references to Klass* anymore");
  1.2951 +        int slot = field->field_index();
  1.2952 +        if (!CallbackInvoker::report_field_reference(o, fld_o, slot)) {
  1.2953 +          return false;
  1.2954 +        }
  1.2955 +      }
  1.2956 +    } else {
  1.2957 +      if (is_reporting_primitive_fields()) {
  1.2958 +        // primitive instance field
  1.2959 +        address addr = (address)o + field->field_offset();
  1.2960 +        int slot = field->field_index();
  1.2961 +        if (!CallbackInvoker::report_primitive_instance_field(o, slot, addr, type)) {
  1.2962 +          return false;
  1.2963 +        }
  1.2964 +      }
  1.2965 +    }
  1.2966 +  }
  1.2967 +
  1.2968 +  // if the object is a java.lang.String
  1.2969 +  if (is_reporting_string_values() &&
  1.2970 +      o->klass() == SystemDictionary::String_klass()) {
  1.2971 +    if (!CallbackInvoker::report_string_value(o)) {
  1.2972 +      return false;
  1.2973 +    }
  1.2974 +  }
  1.2975 +  return true;
  1.2976 +}
  1.2977 +
  1.2978 +
  1.2979 +// Collects all simple (non-stack) roots except for threads;
  1.2980 +// threads are handled in collect_stack_roots() as an optimization.
  1.2981 +// if there's a heap root callback provided then the callback is
  1.2982 +// invoked for each simple root.
  1.2983 +// if an object reference callback is provided then all simple
  1.2984 +// roots are pushed onto the marking stack so that they can be
  1.2985 +// processed later
  1.2986 +//
  1.2987 +inline bool VM_HeapWalkOperation::collect_simple_roots() {
  1.2988 +  SimpleRootsClosure blk;
  1.2989 +
  1.2990 +  // JNI globals
  1.2991 +  blk.set_kind(JVMTI_HEAP_REFERENCE_JNI_GLOBAL);
  1.2992 +  JNIHandles::oops_do(&blk);
  1.2993 +  if (blk.stopped()) {
  1.2994 +    return false;
  1.2995 +  }
  1.2996 +
  1.2997 +  // Preloaded classes and loader from the system dictionary
  1.2998 +  blk.set_kind(JVMTI_HEAP_REFERENCE_SYSTEM_CLASS);
  1.2999 +  SystemDictionary::always_strong_oops_do(&blk);
  1.3000 +  KlassToOopClosure klass_blk(&blk);
  1.3001 +  ClassLoaderDataGraph::always_strong_oops_do(&blk, &klass_blk, false);
  1.3002 +  if (blk.stopped()) {
  1.3003 +    return false;
  1.3004 +  }
  1.3005 +
  1.3006 +  // Inflated monitors
  1.3007 +  blk.set_kind(JVMTI_HEAP_REFERENCE_MONITOR);
  1.3008 +  ObjectSynchronizer::oops_do(&blk);
  1.3009 +  if (blk.stopped()) {
  1.3010 +    return false;
  1.3011 +  }
  1.3012 +
  1.3013 +  // threads are now handled in collect_stack_roots()
  1.3014 +
  1.3015 +  // Other kinds of roots maintained by HotSpot
  1.3016 +  // Many of these won't be visible but others (such as instances of important
  1.3017 +  // exceptions) will be visible.
  1.3018 +  blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER);
  1.3019 +  Universe::oops_do(&blk);
  1.3020 +
  1.3021 +  // If there are any non-perm roots in the code cache, visit them.
  1.3022 +  blk.set_kind(JVMTI_HEAP_REFERENCE_OTHER);
  1.3023 +  CodeBlobToOopClosure look_in_blobs(&blk, false);
  1.3024 +  CodeCache::scavenge_root_nmethods_do(&look_in_blobs);
  1.3025 +
  1.3026 +  return true;
  1.3027 +}
  1.3028 +
  1.3029 +// Walk the stack of a given thread and find all references (locals
  1.3030 +// and JNI calls) and report these as stack references
  1.3031 +inline bool VM_HeapWalkOperation::collect_stack_roots(JavaThread* java_thread,
  1.3032 +                                                      JNILocalRootsClosure* blk)
  1.3033 +{
  1.3034 +  oop threadObj = java_thread->threadObj();
  1.3035 +  assert(threadObj != NULL, "sanity check");
  1.3036 +
  1.3037 +  // only need to get the thread's tag once per thread
  1.3038 +  jlong thread_tag = tag_for(_tag_map, threadObj);
  1.3039 +
  1.3040 +  // also need the thread id
  1.3041 +  jlong tid = java_lang_Thread::thread_id(threadObj);
  1.3042 +
  1.3043 +
  1.3044 +  if (java_thread->has_last_Java_frame()) {
  1.3045 +
  1.3046 +    // vframes are resource allocated
  1.3047 +    Thread* current_thread = Thread::current();
  1.3048 +    ResourceMark rm(current_thread);
  1.3049 +    HandleMark hm(current_thread);
  1.3050 +
  1.3051 +    RegisterMap reg_map(java_thread);
  1.3052 +    frame f = java_thread->last_frame();
  1.3053 +    vframe* vf = vframe::new_vframe(&f, &reg_map, java_thread);
  1.3054 +
  1.3055 +    bool is_top_frame = true;
  1.3056 +    int depth = 0;
  1.3057 +    frame* last_entry_frame = NULL;
  1.3058 +
  1.3059 +    while (vf != NULL) {
  1.3060 +      if (vf->is_java_frame()) {
  1.3061 +
  1.3062 +        // java frame (interpreted, compiled, ...)
  1.3063 +        javaVFrame *jvf = javaVFrame::cast(vf);
  1.3064 +
  1.3065 +        // the jmethodID
  1.3066 +        jmethodID method = jvf->method()->jmethod_id();
  1.3067 +
  1.3068 +        if (!(jvf->method()->is_native())) {
  1.3069 +          jlocation bci = (jlocation)jvf->bci();
  1.3070 +          StackValueCollection* locals = jvf->locals();
  1.3071 +          for (int slot=0; slot<locals->size(); slot++) {
  1.3072 +            if (locals->at(slot)->type() == T_OBJECT) {
  1.3073 +              oop o = locals->obj_at(slot)();
  1.3074 +              if (o == NULL) {
  1.3075 +                continue;
  1.3076 +              }
  1.3077 +
  1.3078 +              // stack reference
  1.3079 +              if (!CallbackInvoker::report_stack_ref_root(thread_tag, tid, depth, method,
  1.3080 +                                                   bci, slot, o)) {
  1.3081 +                return false;
  1.3082 +              }
  1.3083 +            }
  1.3084 +          }
  1.3085 +        } else {
  1.3086 +          blk->set_context(thread_tag, tid, depth, method);
  1.3087 +          if (is_top_frame) {
  1.3088 +            // JNI locals for the top frame.
  1.3089 +            java_thread->active_handles()->oops_do(blk);
  1.3090 +          } else {
  1.3091 +            if (last_entry_frame != NULL) {
  1.3092 +              // JNI locals for the entry frame
  1.3093 +              assert(last_entry_frame->is_entry_frame(), "checking");
  1.3094 +              last_entry_frame->entry_frame_call_wrapper()->handles()->oops_do(blk);
  1.3095 +            }
  1.3096 +          }
  1.3097 +        }
  1.3098 +        last_entry_frame = NULL;
  1.3099 +        depth++;
  1.3100 +      } else {
  1.3101 +        // externalVFrame - for an entry frame then we report the JNI locals
  1.3102 +        // when we find the corresponding javaVFrame
  1.3103 +        frame* fr = vf->frame_pointer();
  1.3104 +        assert(fr != NULL, "sanity check");
  1.3105 +        if (fr->is_entry_frame()) {
  1.3106 +          last_entry_frame = fr;
  1.3107 +        }
  1.3108 +      }
  1.3109 +
  1.3110 +      vf = vf->sender();
  1.3111 +      is_top_frame = false;
  1.3112 +    }
  1.3113 +  } else {
  1.3114 +    // no last java frame but there may be JNI locals
  1.3115 +    blk->set_context(thread_tag, tid, 0, (jmethodID)NULL);
  1.3116 +    java_thread->active_handles()->oops_do(blk);
  1.3117 +  }
  1.3118 +  return true;
  1.3119 +}
  1.3120 +
  1.3121 +
  1.3122 +// Collects the simple roots for all threads and collects all
  1.3123 +// stack roots - for each thread it walks the execution
  1.3124 +// stack to find all references and local JNI refs.
  1.3125 +inline bool VM_HeapWalkOperation::collect_stack_roots() {
  1.3126 +  JNILocalRootsClosure blk;
  1.3127 +  for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) {
  1.3128 +    oop threadObj = thread->threadObj();
  1.3129 +    if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) {
  1.3130 +      // Collect the simple root for this thread before we
  1.3131 +      // collect its stack roots
  1.3132 +      if (!CallbackInvoker::report_simple_root(JVMTI_HEAP_REFERENCE_THREAD,
  1.3133 +                                               threadObj)) {
  1.3134 +        return false;
  1.3135 +      }
  1.3136 +      if (!collect_stack_roots(thread, &blk)) {
  1.3137 +        return false;
  1.3138 +      }
  1.3139 +    }
  1.3140 +  }
  1.3141 +  return true;
  1.3142 +}
  1.3143 +
  1.3144 +// visit an object
  1.3145 +// first mark the object as visited
  1.3146 +// second get all the outbound references from this object (in other words, all
  1.3147 +// the objects referenced by this object).
  1.3148 +//
  1.3149 +bool VM_HeapWalkOperation::visit(oop o) {
  1.3150 +  // mark object as visited
  1.3151 +  assert(!ObjectMarker::visited(o), "can't visit same object more than once");
  1.3152 +  ObjectMarker::mark(o);
  1.3153 +
  1.3154 +  // instance
  1.3155 +  if (o->is_instance()) {
  1.3156 +    if (o->klass() == SystemDictionary::Class_klass()) {
  1.3157 +      if (!java_lang_Class::is_primitive(o)) {
  1.3158 +        // a java.lang.Class
  1.3159 +        return iterate_over_class(o);
  1.3160 +      }
  1.3161 +    } else {
  1.3162 +      return iterate_over_object(o);
  1.3163 +    }
  1.3164 +  }
  1.3165 +
  1.3166 +  // object array
  1.3167 +  if (o->is_objArray()) {
  1.3168 +    return iterate_over_array(o);
  1.3169 +  }
  1.3170 +
  1.3171 +  // type array
  1.3172 +  if (o->is_typeArray()) {
  1.3173 +    return iterate_over_type_array(o);
  1.3174 +  }
  1.3175 +
  1.3176 +  return true;
  1.3177 +}
  1.3178 +
  1.3179 +void VM_HeapWalkOperation::doit() {
  1.3180 +  ResourceMark rm;
  1.3181 +  ObjectMarkerController marker;
  1.3182 +  ClassFieldMapCacheMark cm;
  1.3183 +
  1.3184 +  assert(visit_stack()->is_empty(), "visit stack must be empty");
  1.3185 +
  1.3186 +  // the heap walk starts with an initial object or the heap roots
  1.3187 +  if (initial_object().is_null()) {
  1.3188 +    // If either collect_stack_roots() or collect_simple_roots()
  1.3189 +    // returns false at this point, then there are no mark bits
  1.3190 +    // to reset.
  1.3191 +    ObjectMarker::set_needs_reset(false);
  1.3192 +
  1.3193 +    // Calling collect_stack_roots() before collect_simple_roots()
  1.3194 +    // can result in a big performance boost for an agent that is
  1.3195 +    // focused on analyzing references in the thread stacks.
  1.3196 +    if (!collect_stack_roots()) return;
  1.3197 +
  1.3198 +    if (!collect_simple_roots()) return;
  1.3199 +
  1.3200 +    // no early return so enable heap traversal to reset the mark bits
  1.3201 +    ObjectMarker::set_needs_reset(true);
  1.3202 +  } else {
  1.3203 +    visit_stack()->push(initial_object()());
  1.3204 +  }
  1.3205 +
  1.3206 +  // object references required
  1.3207 +  if (is_following_references()) {
  1.3208 +
  1.3209 +    // visit each object until all reachable objects have been
  1.3210 +    // visited or the callback asked to terminate the iteration.
  1.3211 +    while (!visit_stack()->is_empty()) {
  1.3212 +      oop o = visit_stack()->pop();
  1.3213 +      if (!ObjectMarker::visited(o)) {
  1.3214 +        if (!visit(o)) {
  1.3215 +          break;
  1.3216 +        }
  1.3217 +      }
  1.3218 +    }
  1.3219 +  }
  1.3220 +}
  1.3221 +
  1.3222 +// iterate over all objects that are reachable from a set of roots
  1.3223 +void JvmtiTagMap::iterate_over_reachable_objects(jvmtiHeapRootCallback heap_root_callback,
  1.3224 +                                                 jvmtiStackReferenceCallback stack_ref_callback,
  1.3225 +                                                 jvmtiObjectReferenceCallback object_ref_callback,
  1.3226 +                                                 const void* user_data) {
  1.3227 +  MutexLocker ml(Heap_lock);
  1.3228 +  BasicHeapWalkContext context(heap_root_callback, stack_ref_callback, object_ref_callback);
  1.3229 +  VM_HeapWalkOperation op(this, Handle(), context, user_data);
  1.3230 +  VMThread::execute(&op);
  1.3231 +}
  1.3232 +
  1.3233 +// iterate over all objects that are reachable from a given object
  1.3234 +void JvmtiTagMap::iterate_over_objects_reachable_from_object(jobject object,
  1.3235 +                                                             jvmtiObjectReferenceCallback object_ref_callback,
  1.3236 +                                                             const void* user_data) {
  1.3237 +  oop obj = JNIHandles::resolve(object);
  1.3238 +  Handle initial_object(Thread::current(), obj);
  1.3239 +
  1.3240 +  MutexLocker ml(Heap_lock);
  1.3241 +  BasicHeapWalkContext context(NULL, NULL, object_ref_callback);
  1.3242 +  VM_HeapWalkOperation op(this, initial_object, context, user_data);
  1.3243 +  VMThread::execute(&op);
  1.3244 +}
  1.3245 +
  1.3246 +// follow references from an initial object or the GC roots
  1.3247 +void JvmtiTagMap::follow_references(jint heap_filter,
  1.3248 +                                    KlassHandle klass,
  1.3249 +                                    jobject object,
  1.3250 +                                    const jvmtiHeapCallbacks* callbacks,
  1.3251 +                                    const void* user_data)
  1.3252 +{
  1.3253 +  oop obj = JNIHandles::resolve(object);
  1.3254 +  Handle initial_object(Thread::current(), obj);
  1.3255 +
  1.3256 +  MutexLocker ml(Heap_lock);
  1.3257 +  AdvancedHeapWalkContext context(heap_filter, klass, callbacks);
  1.3258 +  VM_HeapWalkOperation op(this, initial_object, context, user_data);
  1.3259 +  VMThread::execute(&op);
  1.3260 +}
  1.3261 +
  1.3262 +
  1.3263 +void JvmtiTagMap::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) {
  1.3264 +  // No locks during VM bring-up (0 threads) and no safepoints after main
  1.3265 +  // thread creation and before VMThread creation (1 thread); initial GC
  1.3266 +  // verification can happen in that window which gets to here.
  1.3267 +  assert(Threads::number_of_threads() <= 1 ||
  1.3268 +         SafepointSynchronize::is_at_safepoint(),
  1.3269 +         "must be executed at a safepoint");
  1.3270 +  if (JvmtiEnv::environments_might_exist()) {
  1.3271 +    JvmtiEnvIterator it;
  1.3272 +    for (JvmtiEnvBase* env = it.first(); env != NULL; env = it.next(env)) {
  1.3273 +      JvmtiTagMap* tag_map = env->tag_map();
  1.3274 +      if (tag_map != NULL && !tag_map->is_empty()) {
  1.3275 +        tag_map->do_weak_oops(is_alive, f);
  1.3276 +      }
  1.3277 +    }
  1.3278 +  }
  1.3279 +}
  1.3280 +
  1.3281 +void JvmtiTagMap::do_weak_oops(BoolObjectClosure* is_alive, OopClosure* f) {
  1.3282 +
  1.3283 +  // does this environment have the OBJECT_FREE event enabled
  1.3284 +  bool post_object_free = env()->is_enabled(JVMTI_EVENT_OBJECT_FREE);
  1.3285 +
  1.3286 +  // counters used for trace message
  1.3287 +  int freed = 0;
  1.3288 +  int moved = 0;
  1.3289 +
  1.3290 +  JvmtiTagHashmap* hashmap = this->hashmap();
  1.3291 +
  1.3292 +  // reenable sizing (if disabled)
  1.3293 +  hashmap->set_resizing_enabled(true);
  1.3294 +
  1.3295 +  // if the hashmap is empty then we can skip it
  1.3296 +  if (hashmap->_entry_count == 0) {
  1.3297 +    return;
  1.3298 +  }
  1.3299 +
  1.3300 +  // now iterate through each entry in the table
  1.3301 +
  1.3302 +  JvmtiTagHashmapEntry** table = hashmap->table();
  1.3303 +  int size = hashmap->size();
  1.3304 +
  1.3305 +  JvmtiTagHashmapEntry* delayed_add = NULL;
  1.3306 +
  1.3307 +  for (int pos = 0; pos < size; ++pos) {
  1.3308 +    JvmtiTagHashmapEntry* entry = table[pos];
  1.3309 +    JvmtiTagHashmapEntry* prev = NULL;
  1.3310 +
  1.3311 +    while (entry != NULL) {
  1.3312 +      JvmtiTagHashmapEntry* next = entry->next();
  1.3313 +
  1.3314 +      oop* obj = entry->object_addr();
  1.3315 +
  1.3316 +      // has object been GC'ed
  1.3317 +      if (!is_alive->do_object_b(entry->object())) {
  1.3318 +        // grab the tag
  1.3319 +        jlong tag = entry->tag();
  1.3320 +        guarantee(tag != 0, "checking");
  1.3321 +
  1.3322 +        // remove GC'ed entry from hashmap and return the
  1.3323 +        // entry to the free list
  1.3324 +        hashmap->remove(prev, pos, entry);
  1.3325 +        destroy_entry(entry);
  1.3326 +
  1.3327 +        // post the event to the profiler
  1.3328 +        if (post_object_free) {
  1.3329 +          JvmtiExport::post_object_free(env(), tag);
  1.3330 +        }
  1.3331 +
  1.3332 +        ++freed;
  1.3333 +      } else {
  1.3334 +        f->do_oop(entry->object_addr());
  1.3335 +        oop new_oop = entry->object();
  1.3336 +
  1.3337 +        // if the object has moved then re-hash it and move its
  1.3338 +        // entry to its new location.
  1.3339 +        unsigned int new_pos = JvmtiTagHashmap::hash(new_oop, size);
  1.3340 +        if (new_pos != (unsigned int)pos) {
  1.3341 +          if (prev == NULL) {
  1.3342 +            table[pos] = next;
  1.3343 +          } else {
  1.3344 +            prev->set_next(next);
  1.3345 +          }
  1.3346 +          if (new_pos < (unsigned int)pos) {
  1.3347 +            entry->set_next(table[new_pos]);
  1.3348 +            table[new_pos] = entry;
  1.3349 +          } else {
  1.3350 +            // Delay adding this entry to it's new position as we'd end up
  1.3351 +            // hitting it again during this iteration.
  1.3352 +            entry->set_next(delayed_add);
  1.3353 +            delayed_add = entry;
  1.3354 +          }
  1.3355 +          moved++;
  1.3356 +        } else {
  1.3357 +          // object didn't move
  1.3358 +          prev = entry;
  1.3359 +        }
  1.3360 +      }
  1.3361 +
  1.3362 +      entry = next;
  1.3363 +    }
  1.3364 +  }
  1.3365 +
  1.3366 +  // Re-add all the entries which were kept aside
  1.3367 +  while (delayed_add != NULL) {
  1.3368 +    JvmtiTagHashmapEntry* next = delayed_add->next();
  1.3369 +    unsigned int pos = JvmtiTagHashmap::hash(delayed_add->object(), size);
  1.3370 +    delayed_add->set_next(table[pos]);
  1.3371 +    table[pos] = delayed_add;
  1.3372 +    delayed_add = next;
  1.3373 +  }
  1.3374 +
  1.3375 +  // stats
  1.3376 +  if (TraceJVMTIObjectTagging) {
  1.3377 +    int post_total = hashmap->_entry_count;
  1.3378 +    int pre_total = post_total + freed;
  1.3379 +
  1.3380 +    tty->print_cr("(%d->%d, %d freed, %d total moves)",
  1.3381 +        pre_total, post_total, freed, moved);
  1.3382 +  }
  1.3383 +}

mercurial