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