src/share/vm/classfile/loaderConstraints.cpp

Tue, 23 Nov 2010 13:22:55 -0800

author
stefank
date
Tue, 23 Nov 2010 13:22:55 -0800
changeset 2314
f95d63e2154a
parent 1907
c18cbe5936b8
child 2497
3582bf76420e
permissions
-rw-r--r--

6989984: Use standard include model for Hospot
Summary: Replaced MakeDeps and the includeDB files with more standardized solutions.
Reviewed-by: coleenp, kvn, kamg

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

mercurial