001 /* 002 * This file is part of the Jikes RVM project (http://jikesrvm.org). 003 * 004 * This file is licensed to You under the Eclipse Public License (EPL); 005 * You may not use this file except in compliance with the License. You 006 * may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/eclipse-1.0.php 009 * 010 * See the COPYRIGHT.txt file distributed with this work for information 011 * regarding copyright ownership. 012 */ 013 package org.jikesrvm; 014 015 import java.util.Enumeration; 016 import org.jikesrvm.classloader.Atom; 017 import org.jikesrvm.classloader.RVMClass; 018 import org.jikesrvm.classloader.RVMMethod; 019 import org.jikesrvm.classloader.RVMType; 020 import org.jikesrvm.scheduler.RVMThread; 021 022 /** 023 * A class for managing various callbacks from the VM. 024 * 025 * <p>Consumers should register an implementation of the needed interface with 026 * a given callback method, and will get notified when the event happens. 027 * 028 * <p>Note: callback consumers should not rely on any particular order of 029 * callback invocation. 030 * 031 * <p>TODO: allow limited control over callback order. 032 * 033 * <p> 034 * The following events are currently implemented. See code for exact 035 * invocation syntax. 036 * <ul> 037 * <li> ClassLoaded - called after a RVMClass is loaded 038 * <li> ClassResolved - called after a RVMClass is resolved 039 * <li> ClassInstantiated - called after a RVMClass is instantiated 040 * <li> ClassInitialized - called after a RVMClass is initialized 041 * <li> MethodOverride - called when a method in a newly loaded class 042 * overrides a method in an existing class 043 * <li> MethodCompile - called before a method is compiled 044 * <li> ForName - called when java.lang.Class.forName() is invoked 045 * <li> BootImageWriting - called when boot image writing is started 046 * <li> Startup - called when the VM has completed booting 047 * <li> Exit - called when the VM is about to exit (note: this is very fragile; TODO: remove???) 048 * <li> AppStart - called before the application starts executing 049 * all runs -- needs application support) 050 * <li> AppComplete - called after the application completes executing 051 * all runs --- needs application support) 052 * <li> AppRunStart - called before the application starts a run 053 * (many applications have several runs -- needs 054 * application support) 055 * <li> AppRunComplete - called after the application completes a run 056 * (many applications have several runs --- needs 057 * application support) 058 * <li> RecompileAllDynamicallyLoadedMethods - called when the application 059 * wants to recompile all methods that were previously 060 * dynamically compiled. Could be useful for 061 * studying the the impact of how much of 062 * class hierarchy being loaded effects compilation 063 * performance 064 * (application must call this explicitly for anything 065 * to happen) 066 * </ul> 067 */ 068 public final class Callbacks { 069 /////////////// 070 // INTERFACE // 071 /////////////// 072 073 /** 074 * Interface for monitoring class loading. 075 */ 076 public interface ClassLoadedMonitor { 077 /** 078 * Notify the monitor that a class has been loaded. 079 * @param klass the class that was loaded 080 */ 081 void notifyClassLoaded(RVMClass klass); 082 } 083 084 /** 085 * Class loading callback list. 086 */ 087 private static CallbackList classLoadedCallbacks = null; 088 private static final Object classLoadedLock = new Object(); 089 private static boolean classLoadedEnabled = true; 090 091 /** 092 * Register a callback for class loading. 093 * @param cb the object to notify when event happens 094 */ 095 public static void addClassLoadedMonitor(ClassLoadedMonitor cb) { 096 synchronized (classLoadedLock) { 097 if (TRACE_ADDMONITOR || TRACE_CLASSLOADED) { 098 VM.sysWrite("adding class loaded monitor: "); 099 VM.sysWrite(getClass(cb)); 100 VM.sysWrite("\n"); 101 } 102 classLoadedCallbacks = new CallbackList(cb, classLoadedCallbacks); 103 } 104 } 105 106 /** 107 * Notify the callback manager that a class has been loaded. 108 * @param klass the class that was loaded 109 */ 110 public static void notifyClassLoaded(RVMClass klass) { 111 // NOTE: will need synchronization if allowing unregistering 112 if (!classLoadedEnabled) return; 113 classLoadedEnabled = false; 114 if (TRACE_CLASSLOADED) { 115 //VM.sysWrite(getThread(), false); 116 //VM.sysWrite(": "); 117 VM.sysWrite("invoking class loaded monitors: "); 118 VM.sysWrite(klass.getDescriptor()); 119 VM.sysWrite("\n"); 120 //printStack("From: "); 121 } 122 for (CallbackList l = classLoadedCallbacks; l != null; l = l.next) { 123 if (TRACE_CLASSLOADED) { 124 VM.sysWrite(" "); 125 VM.sysWrite(getClass(l.callback)); 126 VM.sysWrite("\n"); 127 } 128 ((ClassLoadedMonitor) l.callback).notifyClassLoaded(klass); 129 } 130 classLoadedEnabled = true; 131 } 132 133 /** 134 * Interface for monitoring class resolution. 135 */ 136 public interface ClassResolvedMonitor { 137 /** 138 * Notify the monitor that a class has been resolved. 139 * @param klass the class that was resolved 140 */ 141 void notifyClassResolved(RVMClass klass); 142 } 143 144 /** 145 * Class resolution callback list. 146 */ 147 private static CallbackList classResolvedCallbacks = null; 148 private static final Object classResolvedLock = new Object(); 149 private static boolean classResolvedEnabled = true; 150 151 /** 152 * Register a callback for class resolution. 153 * @param cb the object to notify when event happens 154 */ 155 public static void addClassResolvedMonitor(ClassResolvedMonitor cb) { 156 synchronized (classResolvedLock) { 157 if (TRACE_ADDMONITOR || TRACE_CLASSRESOLVED) { 158 VM.sysWrite("adding class resolved monitor: "); 159 VM.sysWrite(getClass(cb)); 160 VM.sysWrite("\n"); 161 } 162 classResolvedCallbacks = new CallbackList(cb, classResolvedCallbacks); 163 } 164 } 165 166 /** 167 * Notify the callback manager that a class has been resolved. 168 * @param klass the class that was resolved 169 */ 170 public static void notifyClassResolved(RVMClass klass) { 171 // NOTE: will need synchronization if allowing unregistering 172 if (!classResolvedEnabled) return; 173 classResolvedEnabled = false; 174 if (TRACE_CLASSRESOLVED) { 175 //VM.sysWrite(getThread(), false); 176 //VM.sysWrite(": "); 177 VM.sysWrite("invoking class resolved monitors: "); 178 VM.sysWrite(klass.getDescriptor()); 179 VM.sysWrite("\n"); 180 //printStack("From: "); 181 } 182 for (CallbackList l = classResolvedCallbacks; l != null; l = l.next) { 183 if (TRACE_CLASSRESOLVED) { 184 VM.sysWrite(" "); 185 VM.sysWrite(getClass(l.callback)); 186 VM.sysWrite("\n"); 187 } 188 ((ClassResolvedMonitor) l.callback).notifyClassResolved(klass); 189 } 190 classResolvedEnabled = true; 191 } 192 193 /** 194 * Interface for monitoring class instantiation. 195 */ 196 public interface ClassInstantiatedMonitor { 197 /** 198 * Notify the monitor that a class has been instantiated. 199 * @param klass the class that was instantiated 200 */ 201 void notifyClassInstantiated(RVMClass klass); 202 } 203 204 /** 205 * Class instantiation callback list. 206 */ 207 private static CallbackList classInstantiatedCallbacks = null; 208 private static final Object classInstantiatedLock = new Object(); 209 private static boolean classInstantiatedEnabled = true; 210 211 /** 212 * Register a callback for class instantiation. 213 * @param cb the object to notify when event happens 214 */ 215 public static void addClassInstantiatedMonitor(ClassInstantiatedMonitor cb) { 216 synchronized (classInstantiatedLock) { 217 if (TRACE_ADDMONITOR || TRACE_CLASSINSTANTIATED) { 218 VM.sysWrite("adding class instantiated monitor: "); 219 VM.sysWrite(getClass(cb)); 220 VM.sysWrite("\n"); 221 } 222 classInstantiatedCallbacks = new CallbackList(cb, classInstantiatedCallbacks); 223 } 224 } 225 226 /** 227 * Notify the callback manager that a class has been instantiated. 228 * @param klass the class that was instantiated 229 */ 230 public static void notifyClassInstantiated(RVMClass klass) { 231 // NOTE: will need synchronization if allowing unregistering 232 if (!classInstantiatedEnabled) return; 233 classInstantiatedEnabled = false; 234 if (TRACE_CLASSINSTANTIATED) { 235 //VM.sysWrite(getThread(), false); 236 //VM.sysWrite(": "); 237 VM.sysWrite("invoking class instantiated monitors: "); 238 VM.sysWrite(klass.getDescriptor()); 239 VM.sysWrite("\n"); 240 //printStack("From: "); 241 } 242 for (CallbackList l = classInstantiatedCallbacks; l != null; l = l.next) { 243 if (TRACE_CLASSINSTANTIATED) { 244 VM.sysWrite(" "); 245 VM.sysWrite(getClass(l.callback)); 246 VM.sysWrite("\n"); 247 } 248 ((ClassInstantiatedMonitor) l.callback).notifyClassInstantiated(klass); 249 } 250 classInstantiatedEnabled = true; 251 } 252 253 /** 254 * Interface for monitoring class initialization. 255 */ 256 public interface ClassInitializedMonitor { 257 /** 258 * Notify the monitor that a class has been initialized. 259 * @param klass the class that was initialized 260 */ 261 void notifyClassInitialized(RVMClass klass); 262 } 263 264 /** 265 * Class initialization callback list. 266 */ 267 private static CallbackList classInitializedCallbacks = null; 268 private static final Object classInitializedLock = new Object(); 269 private static boolean classInitializedEnabled = true; 270 271 /** 272 * Register a callback for class initialization. 273 * @param cb the object to notify when event happens 274 */ 275 public static void addClassInitializedMonitor(ClassInitializedMonitor cb) { 276 synchronized (classInitializedLock) { 277 if (TRACE_ADDMONITOR || TRACE_CLASSINITIALIZED) { 278 VM.sysWrite("adding class initialized monitor: "); 279 VM.sysWrite(getClass(cb)); 280 VM.sysWrite("\n"); 281 } 282 classInitializedCallbacks = new CallbackList(cb, classInitializedCallbacks); 283 } 284 } 285 286 /** 287 * Notify the callback manager that a class has been initialized. 288 * @param klass the class that was initialized 289 */ 290 public static void notifyClassInitialized(RVMClass klass) { 291 // NOTE: will need synchronization if allowing unregistering 292 if (!classInitializedEnabled) return; 293 classInitializedEnabled = false; 294 if (TRACE_CLASSINITIALIZED) { 295 //VM.sysWrite(getThread(), false); 296 //VM.sysWrite(": "); 297 VM.sysWrite("invoking class initialized monitors: "); 298 VM.sysWrite(klass.getDescriptor()); 299 VM.sysWrite("\n"); 300 //printStack("From: "); 301 } 302 for (CallbackList l = classInitializedCallbacks; l != null; l = l.next) { 303 if (TRACE_CLASSINITIALIZED) { 304 VM.sysWrite(" "); 305 VM.sysWrite(getClass(l.callback)); 306 VM.sysWrite("\n"); 307 } 308 ((ClassInitializedMonitor) l.callback).notifyClassInitialized(klass); 309 } 310 classInitializedEnabled = true; 311 } 312 313 /** 314 * Interface for monitoring method override. 315 */ 316 public interface MethodOverrideMonitor { 317 /** 318 * Notify the monitor that a method has been overridden. 319 * @param method the method that was loaded 320 * @param parent the method that it overrides (null if none) 321 */ 322 void notifyMethodOverride(RVMMethod method, RVMMethod parent); 323 } 324 325 /** 326 * Method override callback list. 327 */ 328 private static CallbackList methodOverrideCallbacks = null; 329 private static final Object methodOverrideLock = new Object(); 330 private static boolean methodOverrideEnabled = true; 331 332 /** 333 * Register a callback for method override. 334 * @param cb the object to notify when event happens 335 */ 336 public static void addMethodOverrideMonitor(MethodOverrideMonitor cb) { 337 synchronized (methodOverrideLock) { 338 if (TRACE_ADDMONITOR || TRACE_METHODOVERRIDE) { 339 VM.sysWrite("adding method override monitor: "); 340 VM.sysWrite(getClass(cb)); 341 VM.sysWrite("\n"); 342 } 343 methodOverrideCallbacks = new CallbackList(cb, methodOverrideCallbacks); 344 } 345 } 346 347 /** 348 * Notify the callback manager that a method has been overridden. 349 * @param method the method that was loaded 350 * @param parent the method that it overrides (null if none) 351 */ 352 public static void notifyMethodOverride(RVMMethod method, RVMMethod parent) { 353 // NOTE: will need synchronization if allowing unregistering 354 if (!methodOverrideEnabled) return; 355 methodOverrideEnabled = false; 356 if (TRACE_METHODOVERRIDE) { 357 //VM.sysWrite(getThread(), false); 358 //VM.sysWrite(": "); 359 VM.sysWrite("invoking method override monitors: "); 360 VM.sysWrite(method); 361 VM.sysWrite(":"); 362 if (parent != null) { 363 VM.sysWrite(parent); 364 } else { 365 VM.sysWrite("null"); 366 } 367 VM.sysWrite("\n"); 368 //printStack("From: "); 369 } 370 for (CallbackList l = methodOverrideCallbacks; l != null; l = l.next) { 371 if (TRACE_METHODOVERRIDE) { 372 VM.sysWrite(" "); 373 VM.sysWrite(getClass(l.callback)); 374 VM.sysWrite("\n"); 375 } 376 ((MethodOverrideMonitor) l.callback).notifyMethodOverride(method, parent); 377 } 378 methodOverrideEnabled = true; 379 } 380 381 /** 382 * Interface for monitoring method compile. 383 */ 384 public interface MethodCompileMonitor { 385 /** 386 * Notify the monitor that a method is about to be compiled. 387 * NOTE: use VM.runningVM and VM.writingBootImage to determine 388 * whether the VM is running 389 * @param method the method that will be compiled 390 * @param compiler the compiler that will be invoked. 391 * Values are constants in CompiledMethod 392 */ 393 void notifyMethodCompile(RVMMethod method, int compiler); 394 } 395 396 /** 397 * Method compile callback list. 398 */ 399 private static CallbackList methodCompileCallbacks = null; 400 private static final Object methodCompileLock = new Object(); 401 private static boolean methodCompileEnabled = true; 402 403 /** 404 * Register a callback for method compile. 405 * @param cb the object to notify when event happens 406 */ 407 public static void addMethodCompileMonitor(MethodCompileMonitor cb) { 408 synchronized (methodCompileLock) { 409 if (TRACE_ADDMONITOR || TRACE_METHODCOMPILE) { 410 VM.sysWrite("adding method compile monitor: "); 411 VM.sysWrite(getClass(cb)); 412 VM.sysWrite("\n"); 413 } 414 methodCompileCallbacks = new CallbackList(cb, methodCompileCallbacks); 415 } 416 } 417 418 /** 419 * Notify the callback manager that a method is about to be compiled. 420 * NOTE: use VM.runningVM and VM.writingBootImage to determine 421 * whether the VM is running 422 * @param method the method that will be compiled 423 * @param compiler the compiler that will be invoked 424 * Values are constants in CompiledMethod 425 */ 426 public static void notifyMethodCompile(RVMMethod method, int compiler) { 427 // NOTE: will need synchronization if allowing unregistering 428 if (!methodCompileEnabled) return; 429 methodCompileEnabled = false; 430 if (TRACE_METHODCOMPILE) { 431 //VM.sysWrite(getThread(), false); 432 //VM.sysWrite(": "); 433 VM.sysWrite("invoking method compile monitors: "); 434 VM.sysWrite(method); 435 VM.sysWrite(":"); 436 VM.sysWrite(compiler); 437 VM.sysWrite("\n"); 438 //printStack("From: "); 439 } 440 for (CallbackList l = methodCompileCallbacks; l != null; l = l.next) { 441 if (TRACE_METHODCOMPILE) { 442 VM.sysWrite(" "); 443 VM.sysWrite(getClass(l.callback)); 444 VM.sysWrite("\n"); 445 } 446 ((MethodCompileMonitor) l.callback).notifyMethodCompile(method, compiler); 447 } 448 methodCompileEnabled = true; 449 } 450 451 /** 452 * Interface for monitoring forName calls. 453 */ 454 public interface ForNameMonitor { 455 /** 456 * Notify the monitor that java.lang.Class.forName was called. 457 * @param type the type that will be returned 458 */ 459 void notifyForName(RVMType type); 460 } 461 462 /** 463 * forName call callback list. 464 */ 465 private static CallbackList forNameCallbacks = null; 466 private static final Object forNameLock = new Object(); 467 private static boolean forNameEnabled = true; 468 469 /** 470 * Register a callback for forName call. 471 * @param cb the object to notify when event happens 472 */ 473 public static void addForNameMonitor(ForNameMonitor cb) { 474 synchronized (forNameLock) { 475 if (TRACE_ADDMONITOR || TRACE_FORNAME) { 476 VM.sysWrite("adding forName monitor: "); 477 VM.sysWrite(getClass(cb)); 478 VM.sysWrite("\n"); 479 } 480 forNameCallbacks = new CallbackList(cb, forNameCallbacks); 481 } 482 } 483 484 /** 485 * Notify the monitor that java.lang.Class.forName was called. 486 * @param type the type that will be returned 487 */ 488 public static void notifyForName(RVMType type) { 489 // NOTE: will need synchronization if allowing unregistering 490 if (!forNameEnabled) return; 491 forNameEnabled = false; 492 if (TRACE_FORNAME) { 493 //VM.sysWrite(getThread(), false); 494 //VM.sysWrite(": "); 495 VM.sysWrite("invoking forName monitors: "); 496 VM.sysWrite(type.getDescriptor()); 497 VM.sysWrite("\n"); 498 //printStack("From: "); 499 } 500 for (CallbackList l = forNameCallbacks; l != null; l = l.next) { 501 if (TRACE_FORNAME) { 502 VM.sysWrite(" "); 503 VM.sysWrite(getClass(l.callback)); 504 VM.sysWrite("\n"); 505 } 506 ((ForNameMonitor) l.callback).notifyForName(type); 507 } 508 forNameEnabled = true; 509 } 510 511 /** 512 * Interface for monitoring defineClass calls. 513 */ 514 public interface DefineClassMonitor { 515 /** 516 * Notify the monitor that java.lang.Class.defineclass was called. 517 * @param type the type that will be returned 518 */ 519 void notifyDefineClass(RVMType type); 520 } 521 522 /** 523 * defineclass call callback list. 524 */ 525 private static CallbackList defineClassCallbacks = null; 526 private static final Object defineClassLock = new Object(); 527 private static boolean defineClassEnabled = true; 528 529 /** 530 * Register a callback for defineClass call. 531 * @param cb the object to notify when event happens 532 */ 533 public static void addDefineClassMonitor(DefineClassMonitor cb) { 534 synchronized (defineClassLock) { 535 if (TRACE_ADDMONITOR || TRACE_DEFINECLASS) { 536 VM.sysWrite("adding defineclass monitor: "); 537 VM.sysWrite(getClass(cb)); 538 VM.sysWrite("\n"); 539 } 540 defineClassCallbacks = new CallbackList(cb, defineClassCallbacks); 541 } 542 } 543 544 /** 545 * Notify the monitor that java.lang.Class.defineclass was called. 546 * @param type the type that will be returned 547 */ 548 public static void notifyDefineClass(RVMType type) { 549 // NOTE: will need synchronization if allowing unregistering 550 if (!defineClassEnabled) return; 551 defineClassEnabled = false; 552 if (TRACE_DEFINECLASS) { 553 //VM.sysWrite(getThread(), false); 554 //VM.sysWrite(": "); 555 VM.sysWrite("invoking defineclass monitors: "); 556 VM.sysWrite(type.getDescriptor()); 557 VM.sysWrite("\n"); 558 //printStack("From: "); 559 } 560 for (CallbackList l = defineClassCallbacks; l != null; l = l.next) { 561 if (TRACE_DEFINECLASS) { 562 VM.sysWrite(" "); 563 VM.sysWrite(getClass(l.callback)); 564 VM.sysWrite("\n"); 565 } 566 ((DefineClassMonitor) l.callback).notifyDefineClass(type); 567 } 568 defineClassEnabled = true; 569 } 570 571 /** 572 * Interface for monitoring loadClass calls. 573 */ 574 public interface LoadClassMonitor { 575 /** 576 * Notify the monitor that java.lang.Class.loadclass was called. 577 * @param type the type that will be returned 578 */ 579 void notifyLoadClass(RVMType type); 580 } 581 582 /** 583 * loadclass call callback list. 584 */ 585 private static CallbackList loadClassCallbacks = null; 586 private static final Object loadClassLock = new Object(); 587 private static boolean loadClassEnabled = true; 588 589 /** 590 * Register a callback for loadClass call. 591 * @param cb the object to notify when event happens 592 */ 593 public static void addLoadClassMonitor(LoadClassMonitor cb) { 594 synchronized (loadClassLock) { 595 if (TRACE_ADDMONITOR || TRACE_LOADCLASS) { 596 VM.sysWrite("adding loadclass monitor: "); 597 VM.sysWrite(getClass(cb)); 598 VM.sysWrite("\n"); 599 } 600 loadClassCallbacks = new CallbackList(cb, loadClassCallbacks); 601 } 602 } 603 604 /** 605 * Notify the monitor that java.lang.Class.loadclass was called. 606 * @param type the type that will be returned 607 */ 608 public static void notifyLoadClass(RVMType type) { 609 // NOTE: will need synchronization if allowing unregistering 610 if (!loadClassEnabled) return; 611 loadClassEnabled = false; 612 if (TRACE_LOADCLASS) { 613 //VM.sysWrite(getThread(), false); 614 //VM.sysWrite(": "); 615 VM.sysWrite("invoking loadclass monitors: "); 616 VM.sysWrite(type.getDescriptor()); 617 VM.sysWrite("\n"); 618 //printStack("From: "); 619 } 620 for (CallbackList l = loadClassCallbacks; l != null; l = l.next) { 621 if (TRACE_LOADCLASS) { 622 VM.sysWrite(" "); 623 VM.sysWrite(getClass(l.callback)); 624 VM.sysWrite("\n"); 625 } 626 ((LoadClassMonitor) l.callback).notifyLoadClass(type); 627 } 628 loadClassEnabled = true; 629 } 630 631 /** 632 * Interface for monitoring boot image writing. 633 */ 634 public interface BootImageMonitor { 635 /** 636 * Notify the monitor that boot image writing is in progress. 637 * @param types the types that are included in the boot image 638 */ 639 void notifyBootImage(Enumeration<String> types); 640 } 641 642 /** 643 * Boot image writing callback list. 644 */ 645 private static CallbackList bootImageCallbacks = null; 646 private static final Object bootImageLock = new Object(); 647 private static boolean bootImageEnabled = true; 648 649 /** 650 * Register a callback for boot image writing. 651 * @param cb the object to notify when event happens 652 */ 653 public static void addBootImageMonitor(BootImageMonitor cb) { 654 synchronized (bootImageLock) { 655 if (TRACE_ADDMONITOR || TRACE_BOOTIMAGE) { 656 VM.sysWrite("adding boot image writing monitor: "); 657 VM.sysWrite(getClass(cb)); 658 VM.sysWrite("\n"); 659 } 660 bootImageCallbacks = new CallbackList(cb, bootImageCallbacks); 661 } 662 } 663 664 /** 665 * Notify the monitor that boot image writing is in progress. 666 * @param types the types that are included in the boot image 667 */ 668 public static void notifyBootImage(Enumeration<String> types) { 669 // NOTE: will need synchronization if allowing unregistering 670 if (!bootImageEnabled) return; 671 bootImageEnabled = false; 672 if (TRACE_BOOTIMAGE) { 673 //VM.sysWrite(getThread(), false); 674 //VM.sysWrite(": "); 675 VM.sysWrite("invoking boot image writing monitors\n"); 676 } 677 for (CallbackList l = bootImageCallbacks; l != null; l = l.next) { 678 if (TRACE_BOOTIMAGE) { 679 VM.sysWrite(" "); 680 VM.sysWrite(getClass(l.callback)); 681 VM.sysWrite("\n"); 682 } 683 ((BootImageMonitor) l.callback).notifyBootImage(types); 684 } 685 bootImageEnabled = true; 686 } 687 688 /** 689 * Interface for monitoring VM startup. 690 */ 691 public interface StartupMonitor { 692 /** 693 * Notify the monitor that the VM has started up. 694 */ 695 void notifyStartup(); 696 } 697 698 /** 699 * VM startup callback list. 700 */ 701 private static CallbackList startupCallbacks = null; 702 private static final Object startupLock = new Object(); 703 private static boolean startupEnabled = true; 704 705 /** 706 * Register a callback for VM startup. 707 * @param cb the object to notify when event happens 708 */ 709 public static void addStartupMonitor(StartupMonitor cb) { 710 synchronized (startupLock) { 711 if (TRACE_ADDMONITOR || TRACE_STARTUP) { 712 VM.sysWrite("adding startup monitor: "); 713 VM.sysWrite(getClass(cb)); 714 VM.sysWrite("\n"); 715 } 716 startupCallbacks = new CallbackList(cb, startupCallbacks); 717 } 718 } 719 720 /** 721 * Notify the callback manager that the VM has started up. 722 * NOTE: Runs in the main thread! 723 */ 724 public static void notifyStartup() { 725 // NOTE: will need synchronization if allowing unregistering 726 if (!startupEnabled) return; 727 startupEnabled = false; 728 if (TRACE_STARTUP) { 729 //VM.sysWrite(getThread(), false); 730 //VM.sysWrite(": "); 731 VM.sysWrite("invoking startup monitors\n"); 732 } 733 for (CallbackList l = startupCallbacks; l != null; l = l.next) { 734 if (TRACE_STARTUP) { 735 VM.sysWrite(" "); 736 VM.sysWrite(getClass(l.callback)); 737 VM.sysWrite("\n"); 738 } 739 ((StartupMonitor) l.callback).notifyStartup(); 740 } 741 startupEnabled = true; 742 } 743 744 /** 745 * Interface for monitoring VM exit. 746 */ 747 public interface ExitMonitor { 748 /** 749 * Notify the monitor that the VM is about to exit. 750 * @param value the exit value 751 */ 752 void notifyExit(int value); 753 } 754 755 /** 756 * VM exit callback list. 757 */ 758 private static CallbackList exitCallbacks = null; 759 private static final Object exitLock = new Object(); 760 private static boolean exitCallbacksStarted = false; 761 762 /** 763 * Register a callback for VM exit. 764 * @param cb the object to notify when event happens 765 */ 766 public static void addExitMonitor(ExitMonitor cb) { 767 synchronized (exitLock) { 768 if (TRACE_ADDMONITOR || TRACE_EXIT) { 769 VM.sysWrite("adding exit monitor: "); 770 VM.sysWrite(getClass(cb)); 771 VM.sysWrite("\n"); 772 } 773 exitCallbacks = new CallbackList(cb, exitCallbacks); 774 } 775 } 776 777 /** 778 * Notify the callback manager that the VM is about to exit. 779 * Will return once all the callbacks are invoked. 780 * @param value the exit value 781 */ 782 public static void notifyExit(final int value) { 783 synchronized (exitLock) { 784 if (exitCallbacksStarted) return; 785 if (exitCallbacks == null) return; 786 exitCallbacksStarted = true; 787 if (TRACE_EXIT) { 788 //VM.sysWrite(Callbacks.getThread(), false); 789 //VM.sysWrite(": "); 790 VM.sysWrite("invoking exit monitors: "); 791 VM.sysWriteln(value); 792 //printStack("From: "); 793 } 794 for (CallbackList l = exitCallbacks; l != null; l = l.next) { 795 if (TRACE_EXIT) { 796 VM.sysWrite(" "); 797 VM.sysWrite(Callbacks.getClass(l.callback)); 798 VM.sysWrite("\n"); 799 } 800 ((ExitMonitor) l.callback).notifyExit(value); 801 } 802 } 803 } 804 805 /** 806 * Interface for monitoring when an application starts executing 807 */ 808 public interface AppStartMonitor { 809 /** 810 * Notify the monitor that the application has started executing 811 * @param app application name 812 */ 813 void notifyAppStart(String app); 814 } 815 816 /** 817 * Application Start executing callback list. 818 */ 819 private static CallbackList appStartCallbacks = null; 820 private static final Object appStartLock = new Object(); 821 822 /** 823 * Register a callback for when the application starts executing 824 * @param cb the object to notify when event happens 825 */ 826 public static void addAppStartMonitor(AppStartMonitor cb) { 827 synchronized (appStartLock) { 828 if (TRACE_ADDMONITOR || TRACE_APP_START) { 829 VM.sysWrite("adding application start monitor: "); 830 VM.sysWrite(getClass(cb)); 831 VM.sysWrite("\n"); 832 } 833 appStartCallbacks = new CallbackList(cb, appStartCallbacks); 834 } 835 } 836 837 /** 838 * Notify the callback manager that the application started executing 839 * Will return once all the callbacks are invoked. 840 * @param app name of application 841 */ 842 public static void notifyAppStart(String app) { 843 synchronized (appStartLock) { 844 if (appStartCallbacks == null) return; 845 if (TRACE_APP_START) { 846 VM.sysWrite("invoking application start monitors\n"); 847 } 848 for (CallbackList l = appStartCallbacks; l != null; l = l.next) { 849 if (TRACE_APP_START) { 850 VM.sysWrite(" "); 851 VM.sysWrite(Callbacks.getClass(l.callback)); 852 VM.sysWrite("\n"); 853 } 854 ((AppStartMonitor) l.callback).notifyAppStart(app); 855 } 856 } 857 } 858 859 /** 860 * Interface for monitoring when an application completes executing 861 */ 862 public interface AppCompleteMonitor { 863 /** 864 * Notify the monitor that the application has completed executing 865 * @param app name of application 866 */ 867 void notifyAppComplete(String app); 868 } 869 870 /** 871 * Application Execution Complete callback list. 872 */ 873 private static CallbackList appCompleteCallbacks = null; 874 private static final Object appCompleteLock = new Object(); 875 876 /** 877 * Register a callback for when the application completes executing 878 * @param cb the object to notify when event happens 879 */ 880 public static void addAppCompleteMonitor(AppCompleteMonitor cb) { 881 synchronized (appCompleteLock) { 882 if (TRACE_ADDMONITOR || TRACE_APP_COMPLETE) { 883 VM.sysWrite("adding application complete monitor: "); 884 VM.sysWrite(getClass(cb)); 885 VM.sysWrite("\n"); 886 } 887 appCompleteCallbacks = new CallbackList(cb, appCompleteCallbacks); 888 } 889 } 890 891 /** 892 * Notify the callback manager that the application completed executing 893 * Will return once all the callbacks are invoked. 894 * @param app name of application 895 */ 896 public static void notifyAppComplete(String app) { 897 synchronized (appCompleteLock) { 898 if (appCompleteCallbacks == null) return; 899 if (TRACE_APP_COMPLETE) { 900 VM.sysWrite("invoking application complete monitors for application "); 901 VM.sysWrite(app); 902 VM.sysWrite("\n"); 903 } 904 for (CallbackList l = appCompleteCallbacks; l != null; l = l.next) { 905 if (TRACE_APP_COMPLETE) { 906 VM.sysWrite(" "); 907 VM.sysWrite(Callbacks.getClass(l.callback)); 908 VM.sysWrite("\n"); 909 } 910 ((AppCompleteMonitor) l.callback).notifyAppComplete(app); 911 } 912 } 913 } 914 915 /** 916 * Interface for monitoring when an application starts a run 917 */ 918 public interface AppRunStartMonitor { 919 /** 920 * Notify the monitor that the application has started a run 921 * @param app application name 922 * @param run run number 923 */ 924 void notifyAppRunStart(String app, int run); 925 } 926 927 /** 928 * Application Run Start callback list. 929 */ 930 private static CallbackList appRunStartCallbacks = null; 931 private static final Object appRunStartLock = new Object(); 932 933 /** 934 * Register a callback for when the application starts a run 935 * @param cb the object to notify when event happens 936 */ 937 public static void addAppRunStartMonitor(AppRunStartMonitor cb) { 938 synchronized (appRunStartLock) { 939 if (TRACE_ADDMONITOR || TRACE_APP_RUN_START) { 940 VM.sysWrite("adding application run start monitor: "); 941 VM.sysWrite(getClass(cb)); 942 VM.sysWrite("\n"); 943 } 944 appRunStartCallbacks = new CallbackList(cb, appRunStartCallbacks); 945 } 946 } 947 948 /** 949 * Notify the callback manager that the application started a run 950 * Will return once all the callbacks are invoked. 951 * @param app application name 952 * @param run run number 953 */ 954 public static void notifyAppRunStart(String app, int run) { 955 synchronized (appRunStartLock) { 956 if (appRunStartCallbacks == null) return; 957 if (TRACE_APP_RUN_START) { 958 //VM.sysWrite(getThread(), false); 959 //VM.sysWrite(": "); 960 VM.sysWrite("invoking the start monitor for application "); 961 VM.sysWrite(app); 962 VM.sysWrite(" at run "); 963 VM.sysWrite(run); 964 VM.sysWrite("\n"); 965 } 966 for (CallbackList l = appRunStartCallbacks; l != null; l = l.next) { 967 if (TRACE_APP_RUN_START) { 968 VM.sysWrite(" "); 969 VM.sysWrite(Callbacks.getClass(l.callback)); 970 VM.sysWrite("\n"); 971 } 972 ((AppRunStartMonitor) l.callback).notifyAppRunStart(app, run); 973 } 974 } 975 } 976 977 /** 978 * Interface for monitoring when an application completes a run 979 */ 980 public interface AppRunCompleteMonitor { 981 /** 982 * Notify the monitor that the application has completed a run 983 * @param app name of application 984 * @param run run number 985 */ 986 void notifyAppRunComplete(String app, int run); 987 } 988 989 /** 990 * Application Run Complete callback list. 991 */ 992 private static CallbackList appRunCompleteCallbacks = null; 993 private static final Object appRunCompleteLock = new Object(); 994 995 /** 996 * Register a callback for when the application completes a run 997 * @param cb the object to notify when event happens 998 */ 999 public static void addAppRunCompleteMonitor(AppRunCompleteMonitor cb) { 1000 synchronized (appRunCompleteLock) { 1001 if (TRACE_ADDMONITOR || TRACE_APP_RUN_COMPLETE) { 1002 VM.sysWrite("adding application run complete monitor: "); 1003 VM.sysWrite(getClass(cb)); 1004 VM.sysWrite("\n"); 1005 } 1006 appRunCompleteCallbacks = new CallbackList(cb, appRunCompleteCallbacks); 1007 } 1008 } 1009 1010 /** 1011 * Notify the callback manager that the application completed a run 1012 * Will return once all the callbacks are invoked. 1013 * @param app name of application 1014 * @param run run number 1015 */ 1016 public static void notifyAppRunComplete(String app, int run) { 1017 synchronized (appRunCompleteLock) { 1018 if (appRunCompleteCallbacks == null) return; 1019 if (TRACE_APP_RUN_COMPLETE) { 1020 //VM.sysWrite(getThread(), false); 1021 //VM.sysWrite(": "); 1022 VM.sysWrite("invoking the complete monitor for application ", app); 1023 VM.sysWriteln(" at run ", run); 1024 } 1025 for (CallbackList l = appRunCompleteCallbacks; l != null; l = l.next) { 1026 if (TRACE_APP_RUN_COMPLETE) { 1027 VM.sysWrite(" "); 1028 VM.sysWrite(Callbacks.getClass(l.callback)); 1029 VM.sysWrite("\n"); 1030 } 1031 ((AppRunCompleteMonitor) l.callback).notifyAppRunComplete(app, run); 1032 } 1033 } 1034 } 1035 1036 /** 1037 * Interface for requesting VM to recompile all previously dynamically compiled methods 1038 */ 1039 public interface RecompileAllDynamicallyLoadedMethodsMonitor { 1040 /** 1041 * Notify the monitor that the application has requested the recompile 1042 */ 1043 void notifyRecompileAll(); 1044 } 1045 1046 /** 1047 * Recompile all callback list. 1048 */ 1049 private static CallbackList recompileAllCallbacks = null; 1050 private static final Object recompileAllLock = new Object(); 1051 1052 /** 1053 * Register a callback for when the application requests to recompile all 1054 * dynamically loaded classes 1055 * @param cb the object to notify when event happens 1056 */ 1057 public static void addRecompileAllDynamicallyLoadedMethodsMonitor(RecompileAllDynamicallyLoadedMethodsMonitor cb) { 1058 synchronized (recompileAllLock) { 1059 if (TRACE_ADDMONITOR || TRACE_RECOMPILE_ALL) { 1060 VM.sysWrite("adding recompile all monitor: "); 1061 VM.sysWrite(getClass(cb)); 1062 VM.sysWrite("\n"); 1063 } 1064 recompileAllCallbacks = new CallbackList(cb, recompileAllCallbacks); 1065 } 1066 } 1067 1068 /** 1069 * Notify the callback manager that the application requested a recompile all 1070 * Will return once all the callbacks are invoked. 1071 */ 1072 public static void recompileAllDynamicallyLoadedMethods() { 1073 synchronized (recompileAllLock) { 1074 if (recompileAllCallbacks == null) return; 1075 if (TRACE_RECOMPILE_ALL) { 1076 VM.sysWriteln("invoking the recompile all monitor"); 1077 } 1078 for (CallbackList l = recompileAllCallbacks; l != null; l = l.next) { 1079 if (TRACE_RECOMPILE_ALL) { 1080 VM.sysWrite(" "); 1081 VM.sysWrite(Callbacks.getClass(l.callback)); 1082 VM.sysWrite("\n"); 1083 } 1084 ((RecompileAllDynamicallyLoadedMethodsMonitor) l.callback).notifyRecompileAll(); 1085 } 1086 } 1087 } 1088 1089 //////////////////// 1090 // IMPLEMENTATION // 1091 //////////////////// 1092 1093 /** 1094 * Initialize callbacks. 1095 */ 1096 public static void init() { } 1097 1098 /** 1099 * Perform boot-time actions. 1100 */ 1101 public static void boot() { } 1102 1103 /** 1104 * Linked list of callbacks. 1105 */ 1106 private static class CallbackList { 1107 public CallbackList(Object cb, CallbackList n) { 1108 callback = cb; 1109 next = n; 1110 } 1111 1112 public final Object callback; 1113 public final CallbackList next; 1114 } 1115 1116 private static final boolean TRACE_ADDMONITOR = false; 1117 private static final boolean TRACE_CLASSLOADED = false; 1118 private static final boolean TRACE_CLASSRESOLVED = false; 1119 private static final boolean TRACE_CLASSINITIALIZED = false; 1120 private static final boolean TRACE_CLASSINSTANTIATED = false; 1121 private static final boolean TRACE_METHODOVERRIDE = false; 1122 private static final boolean TRACE_METHODCOMPILE = false; 1123 private static final boolean TRACE_FORNAME = false; 1124 private static final boolean TRACE_DEFINECLASS = false; 1125 private static final boolean TRACE_LOADCLASS = false; 1126 private static final boolean TRACE_BOOTIMAGE = false; 1127 private static final boolean TRACE_STARTUP = false; 1128 private static final boolean TRACE_EXIT = false; 1129 private static final boolean TRACE_APP_RUN_START = false; 1130 private static final boolean TRACE_APP_RUN_COMPLETE = false; 1131 private static final boolean TRACE_APP_START = false; 1132 private static final boolean TRACE_APP_COMPLETE = false; 1133 private static final boolean TRACE_RECOMPILE_ALL = false; 1134 1135 /** 1136 * Return class name of the object. 1137 * @param o the object 1138 * @return class name of the object 1139 */ 1140 private static Atom getClass(Object o) { 1141 if (VM.runningVM) { 1142 return java.lang.JikesRVMSupport.getTypeForClass(o.getClass()).getDescriptor(); 1143 } else { 1144 return Atom.findOrCreateAsciiAtom(o.getClass().getName()); 1145 } 1146 } 1147 1148 /** 1149 * Return current thread id. 1150 * @return current thread id 1151 */ 1152 @SuppressWarnings("unused") 1153 private static int getThread() { 1154 if (VM.runningVM) { 1155 return RVMThread.getCurrentThread().getThreadSlot(); 1156 } else { 1157 return System.identityHashCode(Thread.currentThread()); 1158 } 1159 } 1160 1161 /** 1162 * Print current stack trace. 1163 * @param message error message 1164 */ 1165 @SuppressWarnings("unused") 1166 private static void printStack(String message) { 1167 if (VM.runningVM) { 1168 RVMThread.traceback(message); 1169 } else { 1170 new Throwable(message).printStackTrace(); 1171 } 1172 } 1173 } 1174