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 */
895 public static void notifyAppComplete(String app) {
896 synchronized (appCompleteLock) {
897 if (appCompleteCallbacks == null) return;
898 if (TRACE_APP_COMPLETE) {
899 VM.sysWrite("invoking application complete monitors for application ");
900 VM.sysWrite(app);
901 VM.sysWrite("\n");
902 }
903 for (CallbackList l = appCompleteCallbacks; l != null; l = l.next) {
904 if (TRACE_APP_COMPLETE) {
905 VM.sysWrite(" ");
906 VM.sysWrite(Callbacks.getClass(l.callback));
907 VM.sysWrite("\n");
908 }
909 ((AppCompleteMonitor) l.callback).notifyAppComplete(app);
910 }
911 }
912 }
913
914 /**
915 * Interface for monitoring when an application starts a run
916 */
917 public interface AppRunStartMonitor {
918 /**
919 * Notify the monitor that the application has started a run
920 * @param app application name
921 * @param run run number
922 */
923 void notifyAppRunStart(String app, int run);
924 }
925
926 /**
927 * Application Run Start callback list.
928 */
929 private static CallbackList appRunStartCallbacks = null;
930 private static final Object appRunStartLock = new Object();
931
932 /**
933 * Register a callback for when the application starts a run
934 * @param cb the object to notify when event happens
935 */
936 public static void addAppRunStartMonitor(AppRunStartMonitor cb) {
937 synchronized (appRunStartLock) {
938 if (TRACE_ADDMONITOR || TRACE_APP_RUN_START) {
939 VM.sysWrite("adding application run start monitor: ");
940 VM.sysWrite(getClass(cb));
941 VM.sysWrite("\n");
942 }
943 appRunStartCallbacks = new CallbackList(cb, appRunStartCallbacks);
944 }
945 }
946
947 /**
948 * Notify the callback manager that the application started a run
949 * Will return once all the callbacks are invoked.
950 */
951 public static void notifyAppRunStart(String app, int run) {
952 synchronized (appRunStartLock) {
953 if (appRunStartCallbacks == null) return;
954 if (TRACE_APP_RUN_START) {
955 //VM.sysWrite(getThread(), false);
956 //VM.sysWrite(": ");
957 VM.sysWrite("invoking the start monitor for application ");
958 VM.sysWrite(app);
959 VM.sysWrite(" at run ");
960 VM.sysWrite(run);
961 VM.sysWrite("\n");
962 }
963 for (CallbackList l = appRunStartCallbacks; l != null; l = l.next) {
964 if (TRACE_APP_RUN_START) {
965 VM.sysWrite(" ");
966 VM.sysWrite(Callbacks.getClass(l.callback));
967 VM.sysWrite("\n");
968 }
969 ((AppRunStartMonitor) l.callback).notifyAppRunStart(app, run);
970 }
971 }
972 }
973
974 /**
975 * Interface for monitoring when an application completes a run
976 */
977 public interface AppRunCompleteMonitor {
978 /**
979 * Notify the monitor that the application has completed a run
980 * @param app name of application
981 * @param run run number
982 */
983 void notifyAppRunComplete(String app, int run);
984 }
985
986 /**
987 * Application Run Complete callback list.
988 */
989 private static CallbackList appRunCompleteCallbacks = null;
990 private static final Object appRunCompleteLock = new Object();
991
992 /**
993 * Register a callback for when the application completes a run
994 * @param cb the object to notify when event happens
995 */
996 public static void addAppRunCompleteMonitor(AppRunCompleteMonitor cb) {
997 synchronized (appRunCompleteLock) {
998 if (TRACE_ADDMONITOR || TRACE_APP_RUN_COMPLETE) {
999 VM.sysWrite("adding application run complete monitor: ");
1000 VM.sysWrite(getClass(cb));
1001 VM.sysWrite("\n");
1002 }
1003 appRunCompleteCallbacks = new CallbackList(cb, appRunCompleteCallbacks);
1004 }
1005 }
1006
1007 /**
1008 * Notify the callback manager that the application completed a run
1009 * Will return once all the callbacks are invoked.
1010 * @param app name of application
1011 * @param run run number
1012 */
1013 public static void notifyAppRunComplete(String app, int run) {
1014 synchronized (appRunCompleteLock) {
1015 if (appRunCompleteCallbacks == null) return;
1016 if (TRACE_APP_RUN_COMPLETE) {
1017 //VM.sysWrite(getThread(), false);
1018 //VM.sysWrite(": ");
1019 VM.sysWrite("invoking the complete monitor for application ", app);
1020 VM.sysWriteln(" at run ", run);
1021 }
1022 for (CallbackList l = appRunCompleteCallbacks; l != null; l = l.next) {
1023 if (TRACE_APP_RUN_COMPLETE) {
1024 VM.sysWrite(" ");
1025 VM.sysWrite(Callbacks.getClass(l.callback));
1026 VM.sysWrite("\n");
1027 }
1028 ((AppRunCompleteMonitor) l.callback).notifyAppRunComplete(app, run);
1029 }
1030 }
1031 }
1032
1033 /**
1034 * Interface for requesting VM to recompile all previously dynamically compiled methods
1035 */
1036 public interface RecompileAllDynamicallyLoadedMethodsMonitor {
1037 /**
1038 * Notify the monitor that the application has requested the recompile
1039 */
1040 void notifyRecompileAll();
1041 }
1042
1043 /**
1044 * Recompile all callback list.
1045 */
1046 private static CallbackList recompileAllCallbacks = null;
1047 private static final Object recompileAllLock = new Object();
1048
1049 /**
1050 * Register a callback for when the application requests to recompile all
1051 * dynamically loaded classes
1052 * @param cb the object to notify when event happens
1053 */
1054 public static void addRecompileAllDynamicallyLoadedMethodsMonitor(RecompileAllDynamicallyLoadedMethodsMonitor cb) {
1055 synchronized (recompileAllLock) {
1056 if (TRACE_ADDMONITOR || TRACE_RECOMPILE_ALL) {
1057 VM.sysWrite("adding recompile all monitor: ");
1058 VM.sysWrite(getClass(cb));
1059 VM.sysWrite("\n");
1060 }
1061 recompileAllCallbacks = new CallbackList(cb, recompileAllCallbacks);
1062 }
1063 }
1064
1065 /**
1066 * Notify the callback manager that the application requested a recompile all
1067 * Will return once all the callbacks are invoked.
1068 */
1069 public static void recompileAllDynamicallyLoadedMethods() {
1070 synchronized (recompileAllLock) {
1071 if (recompileAllCallbacks == null) return;
1072 if (TRACE_RECOMPILE_ALL) {
1073 VM.sysWriteln("invoking the recompile all monitor");
1074 }
1075 for (CallbackList l = recompileAllCallbacks; l != null; l = l.next) {
1076 if (TRACE_RECOMPILE_ALL) {
1077 VM.sysWrite(" ");
1078 VM.sysWrite(Callbacks.getClass(l.callback));
1079 VM.sysWrite("\n");
1080 }
1081 ((RecompileAllDynamicallyLoadedMethodsMonitor) l.callback).notifyRecompileAll();
1082 }
1083 }
1084 }
1085
1086 ////////////////////
1087 // IMPLEMENTATION //
1088 ////////////////////
1089
1090 /**
1091 * Initialize callbacks.
1092 */
1093 public static void init() { }
1094
1095 /**
1096 * Perform boot-time actions.
1097 */
1098 public static void boot() { }
1099
1100 /**
1101 * Linked list of callbacks.
1102 */
1103 private static class CallbackList {
1104 public CallbackList(Object cb, CallbackList n) {
1105 callback = cb;
1106 next = n;
1107 }
1108
1109 public final Object callback;
1110 public final CallbackList next;
1111 }
1112
1113 private static final boolean TRACE_ADDMONITOR = false;
1114 private static final boolean TRACE_CLASSLOADED = false;
1115 private static final boolean TRACE_CLASSRESOLVED = false;
1116 private static final boolean TRACE_CLASSINITIALIZED = false;
1117 private static final boolean TRACE_CLASSINSTANTIATED = false;
1118 private static final boolean TRACE_METHODOVERRIDE = false;
1119 private static final boolean TRACE_METHODCOMPILE = false;
1120 private static final boolean TRACE_FORNAME = false;
1121 private static final boolean TRACE_DEFINECLASS = false;
1122 private static final boolean TRACE_LOADCLASS = false;
1123 private static final boolean TRACE_BOOTIMAGE = false;
1124 private static final boolean TRACE_STARTUP = false;
1125 private static final boolean TRACE_EXIT = false;
1126 private static final boolean TRACE_APP_RUN_START = false;
1127 private static final boolean TRACE_APP_RUN_COMPLETE = false;
1128 private static final boolean TRACE_APP_START = false;
1129 private static final boolean TRACE_APP_COMPLETE = false;
1130 private static final boolean TRACE_RECOMPILE_ALL = false;
1131
1132 /**
1133 * Return class name of the object.
1134 * @return class name of the object
1135 */
1136 private static Atom getClass(Object o) {
1137 if (VM.runningVM) {
1138 return java.lang.JikesRVMSupport.getTypeForClass(o.getClass()).getDescriptor();
1139 } else {
1140 return Atom.findOrCreateAsciiAtom(o.getClass().getName());
1141 }
1142 }
1143
1144 /**
1145 * Return current thread id.
1146 * @return current thread id
1147 */
1148 @SuppressWarnings("unused")
1149 private static int getThread() {
1150 if (VM.runningVM) {
1151 return RVMThread.getCurrentThread().getThreadSlot();
1152 } else {
1153 return System.identityHashCode(Thread.currentThread());
1154 }
1155 }
1156
1157 /**
1158 * Print current stack trace.
1159 */
1160 @SuppressWarnings("unused")
1161 private static void printStack(String message) {
1162 if (VM.runningVM) {
1163 RVMThread.traceback(message);
1164 } else {
1165 new Throwable(message).printStackTrace();
1166 }
1167 }
1168 }
1169