src/share/vm/classfile/loaderConstraints.cpp

Fri, 27 Feb 2009 13:27:09 -0800

author
twisti
date
Fri, 27 Feb 2009 13:27:09 -0800
changeset 1040
98cb887364d3
parent 435
a61af66fc99e
child 1693
38836cf1d8d2
child 1771
0c3f888b7636
permissions
-rw-r--r--

6810672: Comment typos
Summary: I have collected some typos I have found while looking at the code.
Reviewed-by: kvn, never

duke@435 1 /*
duke@435 2 * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
duke@435 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@435 4 *
duke@435 5 * This code is free software; you can redistribute it and/or modify it
duke@435 6 * under the terms of the GNU General Public License version 2 only, as
duke@435 7 * published by the Free Software Foundation.
duke@435 8 *
duke@435 9 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@435 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@435 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@435 12 * version 2 for more details (a copy is included in the LICENSE file that
duke@435 13 * accompanied this code).
duke@435 14 *
duke@435 15 * You should have received a copy of the GNU General Public License version
duke@435 16 * 2 along with this work; if not, write to the Free Software Foundation,
duke@435 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@435 18 *
duke@435 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@435 20 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@435 21 * have any questions.
duke@435 22 *
duke@435 23 */
duke@435 24
duke@435 25 # include "incls/_precompiled.incl"
duke@435 26 # include "incls/_loaderConstraints.cpp.incl"
duke@435 27
duke@435 28 LoaderConstraintTable::LoaderConstraintTable(int nof_buckets)
duke@435 29 : Hashtable(nof_buckets, sizeof(LoaderConstraintEntry)) {};
duke@435 30
duke@435 31
duke@435 32 LoaderConstraintEntry* LoaderConstraintTable::new_entry(
duke@435 33 unsigned int hash, symbolOop name,
duke@435 34 klassOop klass, int num_loaders,
duke@435 35 int max_loaders) {
duke@435 36 LoaderConstraintEntry* entry;
duke@435 37 entry = (LoaderConstraintEntry*)Hashtable::new_entry(hash, klass);
duke@435 38 entry->set_name(name);
duke@435 39 entry->set_num_loaders(num_loaders);
duke@435 40 entry->set_max_loaders(max_loaders);
duke@435 41 return entry;
duke@435 42 }
duke@435 43
duke@435 44
duke@435 45 void LoaderConstraintTable::oops_do(OopClosure* f) {
duke@435 46 for (int index = 0; index < table_size(); index++) {
duke@435 47 for (LoaderConstraintEntry* probe = bucket(index);
duke@435 48 probe != NULL;
duke@435 49 probe = probe->next()) {
duke@435 50 f->do_oop((oop*)(probe->name_addr()));
duke@435 51 if (probe->klass() != NULL) {
duke@435 52 f->do_oop((oop*)probe->klass_addr());
duke@435 53 }
duke@435 54 for (int n = 0; n < probe->num_loaders(); n++) {
duke@435 55 if (probe->loader(n) != NULL) {
duke@435 56 f->do_oop(probe->loader_addr(n));
duke@435 57 }
duke@435 58 }
duke@435 59 }
duke@435 60 }
duke@435 61 }
duke@435 62
duke@435 63 // We must keep the symbolOop used in the name alive. We'll use the
duke@435 64 // loaders to decide if a particular entry can be purged.
duke@435 65 void LoaderConstraintTable::always_strong_classes_do(OopClosure* blk) {
duke@435 66 // We must keep the symbolOop used in the name alive.
duke@435 67 for (int cindex = 0; cindex < table_size(); cindex++) {
duke@435 68 for (LoaderConstraintEntry* lc_probe = bucket(cindex);
duke@435 69 lc_probe != NULL;
duke@435 70 lc_probe = lc_probe->next()) {
duke@435 71 assert (lc_probe->name() != NULL, "corrupted loader constraint table");
duke@435 72 blk->do_oop((oop*)lc_probe->name_addr());
duke@435 73 }
duke@435 74 }
duke@435 75 }
duke@435 76
duke@435 77
duke@435 78 // The loaderConstraintTable must always be accessed with the
duke@435 79 // SystemDictionary lock held. This is true even for readers as
duke@435 80 // entries in the table could be being dynamically resized.
duke@435 81
duke@435 82 LoaderConstraintEntry** LoaderConstraintTable::find_loader_constraint(
duke@435 83 symbolHandle name, Handle loader) {
duke@435 84
duke@435 85 unsigned int hash = compute_hash(name);
duke@435 86 int index = hash_to_index(hash);
duke@435 87 LoaderConstraintEntry** pp = bucket_addr(index);
duke@435 88 while (*pp) {
duke@435 89 LoaderConstraintEntry* p = *pp;
duke@435 90 if (p->hash() == hash) {
duke@435 91 if (p->name() == name()) {
duke@435 92 for (int i = p->num_loaders() - 1; i >= 0; i--) {
duke@435 93 if (p->loader(i) == loader()) {
duke@435 94 return pp;
duke@435 95 }
duke@435 96 }
duke@435 97 }
duke@435 98 }
duke@435 99 pp = p->next_addr();
duke@435 100 }
duke@435 101 return pp;
duke@435 102 }
duke@435 103
duke@435 104
duke@435 105 void LoaderConstraintTable::purge_loader_constraints(BoolObjectClosure* is_alive) {
duke@435 106 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint")
duke@435 107 // Remove unloaded entries from constraint table
duke@435 108 for (int index = 0; index < table_size(); index++) {
duke@435 109 LoaderConstraintEntry** p = bucket_addr(index);
duke@435 110 while(*p) {
duke@435 111 LoaderConstraintEntry* probe = *p;
duke@435 112 klassOop klass = probe->klass();
duke@435 113 // Remove klass that is no longer alive
duke@435 114 if (klass != NULL && !is_alive->do_object_b(klass)) {
duke@435 115 probe->set_klass(NULL);
duke@435 116 if (TraceLoaderConstraints) {
duke@435 117 ResourceMark rm;
duke@435 118 tty->print_cr("[Purging class object from constraint for name %s,"
duke@435 119 " loader list:",
duke@435 120 probe->name()->as_C_string());
duke@435 121 for (int i = 0; i < probe->num_loaders(); i++) {
duke@435 122 tty->print_cr("[ [%d]: %s", i,
duke@435 123 SystemDictionary::loader_name(probe->loader(i)));
duke@435 124 }
duke@435 125 }
duke@435 126 }
duke@435 127 // Remove entries no longer alive from loader array
duke@435 128 int n = 0;
duke@435 129 while (n < probe->num_loaders()) {
duke@435 130 if (probe->loader(n) != NULL) {
duke@435 131 if (!is_alive->do_object_b(probe->loader(n))) {
duke@435 132 if (TraceLoaderConstraints) {
duke@435 133 ResourceMark rm;
duke@435 134 tty->print_cr("[Purging loader %s from constraint for name %s",
duke@435 135 SystemDictionary::loader_name(probe->loader(n)),
duke@435 136 probe->name()->as_C_string()
duke@435 137 );
duke@435 138 }
duke@435 139
duke@435 140 // Compact array
duke@435 141 int num = probe->num_loaders() - 1;
duke@435 142 probe->set_num_loaders(num);
duke@435 143 probe->set_loader(n, probe->loader(num));
duke@435 144 probe->set_loader(num, NULL);
duke@435 145
duke@435 146 if (TraceLoaderConstraints) {
duke@435 147 ResourceMark rm;
duke@435 148 tty->print_cr("[New loader list:");
duke@435 149 for (int i = 0; i < probe->num_loaders(); i++) {
duke@435 150 tty->print_cr("[ [%d]: %s", i,
duke@435 151 SystemDictionary::loader_name(probe->loader(i)));
duke@435 152 }
duke@435 153 }
duke@435 154
duke@435 155 continue; // current element replaced, so restart without
duke@435 156 // incrementing n
duke@435 157 }
duke@435 158 }
duke@435 159 n++;
duke@435 160 }
duke@435 161 // Check whether entry should be purged
duke@435 162 if (probe->num_loaders() < 2) {
duke@435 163 if (TraceLoaderConstraints) {
duke@435 164 ResourceMark rm;
duke@435 165 tty->print("[Purging complete constraint for name %s\n",
duke@435 166 probe->name()->as_C_string());
duke@435 167 }
duke@435 168
duke@435 169 // Purge entry
duke@435 170 *p = probe->next();
duke@435 171 FREE_C_HEAP_ARRAY(oop, probe->loaders());
duke@435 172 free_entry(probe);
duke@435 173 } else {
duke@435 174 #ifdef ASSERT
duke@435 175 assert(is_alive->do_object_b(probe->name()), "name should be live");
duke@435 176 if (probe->klass() != NULL) {
duke@435 177 assert(is_alive->do_object_b(probe->klass()), "klass should be live");
duke@435 178 }
duke@435 179 for (n = 0; n < probe->num_loaders(); n++) {
duke@435 180 if (probe->loader(n) != NULL) {
duke@435 181 assert(is_alive->do_object_b(probe->loader(n)), "loader should be live");
duke@435 182 }
duke@435 183 }
duke@435 184 #endif
duke@435 185 // Go to next entry
duke@435 186 p = probe->next_addr();
duke@435 187 }
duke@435 188 }
duke@435 189 }
duke@435 190 }
duke@435 191
duke@435 192 bool LoaderConstraintTable::add_entry(symbolHandle class_name,
duke@435 193 klassOop klass1, Handle class_loader1,
duke@435 194 klassOop klass2, Handle class_loader2) {
duke@435 195 int failure_code = 0; // encode different reasons for failing
duke@435 196
duke@435 197 if (klass1 != NULL && klass2 != NULL && klass1 != klass2) {
duke@435 198 failure_code = 1;
duke@435 199 } else {
duke@435 200 klassOop klass = klass1 != NULL ? klass1 : klass2;
duke@435 201
duke@435 202 LoaderConstraintEntry** pp1 = find_loader_constraint(class_name,
duke@435 203 class_loader1);
duke@435 204 if (*pp1 != NULL && (*pp1)->klass() != NULL) {
duke@435 205 if (klass != NULL) {
duke@435 206 if (klass != (*pp1)->klass()) {
duke@435 207 failure_code = 2;
duke@435 208 }
duke@435 209 } else {
duke@435 210 klass = (*pp1)->klass();
duke@435 211 }
duke@435 212 }
duke@435 213
duke@435 214 LoaderConstraintEntry** pp2 = find_loader_constraint(class_name,
duke@435 215 class_loader2);
duke@435 216 if (*pp2 != NULL && (*pp2)->klass() != NULL) {
duke@435 217 if (klass != NULL) {
duke@435 218 if (klass != (*pp2)->klass()) {
duke@435 219 failure_code = 3;
duke@435 220 }
duke@435 221 } else {
duke@435 222 klass = (*pp2)->klass();
duke@435 223 }
duke@435 224 }
duke@435 225
duke@435 226 if (failure_code == 0) {
duke@435 227 if (*pp1 == NULL && *pp2 == NULL) {
duke@435 228 unsigned int hash = compute_hash(class_name);
duke@435 229 int index = hash_to_index(hash);
duke@435 230 LoaderConstraintEntry* p;
duke@435 231 p = new_entry(hash, class_name(), klass, 2, 2);
duke@435 232 p->set_loaders(NEW_C_HEAP_ARRAY(oop, 2));
duke@435 233 p->set_loader(0, class_loader1());
duke@435 234 p->set_loader(1, class_loader2());
duke@435 235 p->set_klass(klass);
duke@435 236 p->set_next(bucket(index));
duke@435 237 set_entry(index, p);
duke@435 238 if (TraceLoaderConstraints) {
duke@435 239 ResourceMark rm;
duke@435 240 tty->print("[Adding new constraint for name: %s, loader[0]: %s,"
duke@435 241 " loader[1]: %s ]\n",
duke@435 242 class_name()->as_C_string(),
duke@435 243 SystemDictionary::loader_name(class_loader1()),
duke@435 244 SystemDictionary::loader_name(class_loader2())
duke@435 245 );
duke@435 246 }
duke@435 247 } else if (*pp1 == *pp2) {
duke@435 248 /* constraint already imposed */
duke@435 249 if ((*pp1)->klass() == NULL) {
duke@435 250 (*pp1)->set_klass(klass);
duke@435 251 if (TraceLoaderConstraints) {
duke@435 252 ResourceMark rm;
duke@435 253 tty->print("[Setting class object in existing constraint for"
duke@435 254 " name: %s and loader %s ]\n",
duke@435 255 class_name()->as_C_string(),
duke@435 256 SystemDictionary::loader_name(class_loader1())
duke@435 257 );
duke@435 258 }
duke@435 259 } else {
duke@435 260 assert((*pp1)->klass() == klass, "loader constraints corrupted");
duke@435 261 }
duke@435 262 } else if (*pp1 == NULL) {
duke@435 263 extend_loader_constraint(*pp2, class_loader1, klass);
duke@435 264 } else if (*pp2 == NULL) {
duke@435 265 extend_loader_constraint(*pp1, class_loader2, klass);
duke@435 266 } else {
duke@435 267 merge_loader_constraints(pp1, pp2, klass);
duke@435 268 }
duke@435 269 }
duke@435 270 }
duke@435 271
duke@435 272 if (failure_code != 0 && TraceLoaderConstraints) {
duke@435 273 ResourceMark rm;
duke@435 274 const char* reason = "";
duke@435 275 switch(failure_code) {
duke@435 276 case 1: reason = "the class objects presented by loader[0] and loader[1]"
duke@435 277 " are different"; break;
duke@435 278 case 2: reason = "the class object presented by loader[0] does not match"
duke@435 279 " the stored class object in the constraint"; break;
duke@435 280 case 3: reason = "the class object presented by loader[1] does not match"
duke@435 281 " the stored class object in the constraint"; break;
duke@435 282 default: reason = "unknown reason code";
duke@435 283 }
duke@435 284 tty->print("[Failed to add constraint for name: %s, loader[0]: %s,"
duke@435 285 " loader[1]: %s, Reason: %s ]\n",
duke@435 286 class_name()->as_C_string(),
duke@435 287 SystemDictionary::loader_name(class_loader1()),
duke@435 288 SystemDictionary::loader_name(class_loader2()),
duke@435 289 reason
duke@435 290 );
duke@435 291 }
duke@435 292
duke@435 293 return failure_code == 0;
duke@435 294 }
duke@435 295
duke@435 296
duke@435 297 // return true if the constraint was updated, false if the constraint is
duke@435 298 // violated
duke@435 299 bool LoaderConstraintTable::check_or_update(instanceKlassHandle k,
duke@435 300 Handle loader,
duke@435 301 symbolHandle name) {
duke@435 302 LoaderConstraintEntry* p = *(find_loader_constraint(name, loader));
duke@435 303 if (p && p->klass() != NULL && p->klass() != k()) {
duke@435 304 if (TraceLoaderConstraints) {
duke@435 305 ResourceMark rm;
duke@435 306 tty->print("[Constraint check failed for name %s, loader %s: "
duke@435 307 "the presented class object differs from that stored ]\n",
duke@435 308 name()->as_C_string(),
duke@435 309 SystemDictionary::loader_name(loader()));
duke@435 310 }
duke@435 311 return false;
duke@435 312 } else {
duke@435 313 if (p && p->klass() == NULL) {
duke@435 314 p->set_klass(k());
duke@435 315 if (TraceLoaderConstraints) {
duke@435 316 ResourceMark rm;
duke@435 317 tty->print("[Updating constraint for name %s, loader %s, "
duke@435 318 "by setting class object ]\n",
duke@435 319 name()->as_C_string(),
duke@435 320 SystemDictionary::loader_name(loader()));
duke@435 321 }
duke@435 322 }
duke@435 323 return true;
duke@435 324 }
duke@435 325 }
duke@435 326
duke@435 327 klassOop LoaderConstraintTable::find_constrained_klass(symbolHandle name,
duke@435 328 Handle loader) {
duke@435 329 LoaderConstraintEntry *p = *(find_loader_constraint(name, loader));
duke@435 330 if (p != NULL && p->klass() != NULL)
duke@435 331 return p->klass();
duke@435 332
duke@435 333 // No constraints, or else no klass loaded yet.
duke@435 334 return NULL;
duke@435 335 }
duke@435 336
duke@435 337
duke@435 338 klassOop LoaderConstraintTable::find_constrained_elem_klass(symbolHandle name,
duke@435 339 symbolHandle elem_name,
duke@435 340 Handle loader,
duke@435 341 TRAPS) {
duke@435 342 LoaderConstraintEntry *p = *(find_loader_constraint(name, loader));
duke@435 343 if (p != NULL) {
duke@435 344 assert(p->klass() == NULL, "Expecting null array klass");
duke@435 345
duke@435 346 // The array name has a constraint, but it will not have a class. Check
duke@435 347 // each loader for an associated elem
duke@435 348 for (int i = 0; i < p->num_loaders(); i++) {
duke@435 349 Handle no_protection_domain;
duke@435 350
duke@435 351 klassOop k = SystemDictionary::find(elem_name, p->loader(i), no_protection_domain, THREAD);
duke@435 352 if (k != NULL) {
duke@435 353 // Return the first elem klass found.
duke@435 354 return k;
duke@435 355 }
duke@435 356 }
duke@435 357 }
duke@435 358
duke@435 359 // No constraints, or else no klass loaded yet.
duke@435 360 return NULL;
duke@435 361 }
duke@435 362
duke@435 363
duke@435 364 void LoaderConstraintTable::ensure_loader_constraint_capacity(
duke@435 365 LoaderConstraintEntry *p,
duke@435 366 int nfree) {
duke@435 367 if (p->max_loaders() - p->num_loaders() < nfree) {
duke@435 368 int n = nfree + p->num_loaders();
duke@435 369 oop* new_loaders = NEW_C_HEAP_ARRAY(oop, n);
duke@435 370 memcpy(new_loaders, p->loaders(), sizeof(oop) * p->num_loaders());
duke@435 371 p->set_max_loaders(n);
duke@435 372 FREE_C_HEAP_ARRAY(oop, p->loaders());
duke@435 373 p->set_loaders(new_loaders);
duke@435 374 }
duke@435 375 }
duke@435 376
duke@435 377
duke@435 378 void LoaderConstraintTable::extend_loader_constraint(LoaderConstraintEntry* p,
duke@435 379 Handle loader,
duke@435 380 klassOop klass) {
duke@435 381 ensure_loader_constraint_capacity(p, 1);
duke@435 382 int num = p->num_loaders();
duke@435 383 p->set_loader(num, loader());
duke@435 384 p->set_num_loaders(num + 1);
duke@435 385 if (TraceLoaderConstraints) {
duke@435 386 ResourceMark rm;
duke@435 387 tty->print("[Extending constraint for name %s by adding loader[%d]: %s %s",
duke@435 388 p->name()->as_C_string(),
duke@435 389 num,
duke@435 390 SystemDictionary::loader_name(loader()),
duke@435 391 (p->klass() == NULL ? " and setting class object ]\n" : " ]\n")
duke@435 392 );
duke@435 393 }
duke@435 394 if (p->klass() == NULL) {
duke@435 395 p->set_klass(klass);
duke@435 396 } else {
duke@435 397 assert(klass == NULL || p->klass() == klass, "constraints corrupted");
duke@435 398 }
duke@435 399 }
duke@435 400
duke@435 401
duke@435 402 void LoaderConstraintTable::merge_loader_constraints(
duke@435 403 LoaderConstraintEntry** pp1,
duke@435 404 LoaderConstraintEntry** pp2,
duke@435 405 klassOop klass) {
duke@435 406 // make sure *pp1 has higher capacity
duke@435 407 if ((*pp1)->max_loaders() < (*pp2)->max_loaders()) {
duke@435 408 LoaderConstraintEntry** tmp = pp2;
duke@435 409 pp2 = pp1;
duke@435 410 pp1 = tmp;
duke@435 411 }
duke@435 412
duke@435 413 LoaderConstraintEntry* p1 = *pp1;
duke@435 414 LoaderConstraintEntry* p2 = *pp2;
duke@435 415
duke@435 416 ensure_loader_constraint_capacity(p1, p2->num_loaders());
duke@435 417
duke@435 418 for (int i = 0; i < p2->num_loaders(); i++) {
duke@435 419 int num = p1->num_loaders();
duke@435 420 p1->set_loader(num, p2->loader(i));
duke@435 421 p1->set_num_loaders(num + 1);
duke@435 422 }
duke@435 423
duke@435 424 if (TraceLoaderConstraints) {
duke@435 425 ResourceMark rm;
duke@435 426 tty->print_cr("[Merged constraints for name %s, new loader list:",
duke@435 427 p1->name()->as_C_string()
duke@435 428 );
duke@435 429
duke@435 430 for (int i = 0; i < p1->num_loaders(); i++) {
duke@435 431 tty->print_cr("[ [%d]: %s", i,
duke@435 432 SystemDictionary::loader_name(p1->loader(i)));
duke@435 433 }
duke@435 434 if (p1->klass() == NULL) {
duke@435 435 tty->print_cr("[... and setting class object]");
duke@435 436 }
duke@435 437 }
duke@435 438
duke@435 439 // p1->klass() will hold NULL if klass, p2->klass(), and old
duke@435 440 // p1->klass() are all NULL. In addition, all three must have
duke@435 441 // matching non-NULL values, otherwise either the constraints would
duke@435 442 // have been violated, or the constraints had been corrupted (and an
duke@435 443 // assertion would fail).
duke@435 444 if (p2->klass() != NULL) {
duke@435 445 assert(p2->klass() == klass, "constraints corrupted");
duke@435 446 }
duke@435 447 if (p1->klass() == NULL) {
duke@435 448 p1->set_klass(klass);
duke@435 449 } else {
duke@435 450 assert(p1->klass() == klass, "constraints corrupted");
duke@435 451 }
duke@435 452
duke@435 453 *pp2 = p2->next();
duke@435 454 FREE_C_HEAP_ARRAY(oop, p2->loaders());
duke@435 455 free_entry(p2);
duke@435 456 return;
duke@435 457 }
duke@435 458
duke@435 459
duke@435 460 void LoaderConstraintTable::verify(Dictionary* dictionary) {
duke@435 461 Thread *thread = Thread::current();
duke@435 462 for (int cindex = 0; cindex < _loader_constraint_size; cindex++) {
duke@435 463 for (LoaderConstraintEntry* probe = bucket(cindex);
duke@435 464 probe != NULL;
duke@435 465 probe = probe->next()) {
duke@435 466 guarantee(probe->name()->is_symbol(), "should be symbol");
duke@435 467 if (probe->klass() != NULL) {
duke@435 468 instanceKlass* ik = instanceKlass::cast(probe->klass());
duke@435 469 guarantee(ik->name() == probe->name(), "name should match");
duke@435 470 symbolHandle name (thread, ik->name());
duke@435 471 Handle loader(thread, ik->class_loader());
duke@435 472 unsigned int d_hash = dictionary->compute_hash(name, loader);
duke@435 473 int d_index = dictionary->hash_to_index(d_hash);
duke@435 474 klassOop k = dictionary->find_class(d_index, d_hash, name, loader);
duke@435 475 guarantee(k == probe->klass(), "klass should be in dictionary");
duke@435 476 }
duke@435 477 for (int n = 0; n< probe->num_loaders(); n++) {
duke@435 478 guarantee(probe->loader(n)->is_oop_or_null(), "should be oop");
duke@435 479 }
duke@435 480 }
duke@435 481 }
duke@435 482 }
duke@435 483
duke@435 484 #ifndef PRODUCT
duke@435 485
duke@435 486 // Called with the system dictionary lock held
duke@435 487 void LoaderConstraintTable::print() {
duke@435 488 ResourceMark rm;
duke@435 489
duke@435 490 assert_locked_or_safepoint(SystemDictionary_lock);
duke@435 491 tty->print_cr("Java loader constraints (entries=%d)", _loader_constraint_size);
duke@435 492 for (int cindex = 0; cindex < _loader_constraint_size; cindex++) {
duke@435 493 for (LoaderConstraintEntry* probe = bucket(cindex);
duke@435 494 probe != NULL;
duke@435 495 probe = probe->next()) {
duke@435 496 tty->print("%4d: ", cindex);
duke@435 497 probe->name()->print();
duke@435 498 tty->print(" , loaders:");
duke@435 499 for (int n = 0; n < probe->num_loaders(); n++) {
duke@435 500 probe->loader(n)->print_value();
duke@435 501 tty->print(", ");
duke@435 502 }
duke@435 503 tty->cr();
duke@435 504 }
duke@435 505 }
duke@435 506 }
duke@435 507 #endif

mercurial