# lib/goog/debug/entrypointregistry.js

1 | // Copyright 2010 The Closure Library Authors. All Rights Reserved.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS-IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 |
15 | /**
16 | * @fileoverview A global registry for entry points into a program,
17 | * so that they can be instrumented. Each module should register their
18 | * entry points with this registry. Designed to be compiled out
19 | * if no instrumentation is requested.
20 | *
21 | * Entry points may be registered before or after a call to
22 | * goog.debug.entryPointRegistry.monitorAll. If an entry point is registered
23 | * later, the existing monitor will instrument the new entry point.
24 | *
25 | * @author nicksantos@google.com (Nick Santos)
26 | */
27 |
28 | goog.provide('goog.debug.EntryPointMonitor');
29 | goog.provide('goog.debug.entryPointRegistry');
30 |
31 | goog.require('goog.asserts');
32 |
33 |
34 |
35 | /**
36 | * @interface
37 | */
38 | goog.debug.EntryPointMonitor = function() {};
39 |
40 |
41 | /**
42 | * Instruments a function.
43 | *
44 | * @param {!Function} fn A function to instrument.
45 | * @return {!Function} The instrumented function.
46 | */
47 | goog.debug.EntryPointMonitor.prototype.wrap;
48 |
49 |
50 | /**
51 | * Try to remove an instrumentation wrapper created by this monitor.
52 | * If the function passed to unwrap is not a wrapper created by this
53 | * monitor, then we will do nothing.
54 | *
55 | * Notice that some wrappers may not be unwrappable. For example, if other
56 | * monitors have applied their own wrappers, then it will be impossible to
57 | * unwrap them because their wrappers will have captured our wrapper.
58 | *
59 | * So it is important that entry points are unwrapped in the reverse
60 | * order that they were wrapped.
61 | *
62 | * @param {!Function} fn A function to unwrap.
63 | * @return {!Function} The unwrapped function, or {@code fn} if it was not
64 | * a wrapped function created by this monitor.
65 | */
66 | goog.debug.EntryPointMonitor.prototype.unwrap;
67 |
68 |
69 | /**
70 | * An array of entry point callbacks.
71 | * @type {!Array<function(!Function)>}
72 | * @private
73 | */
74 | goog.debug.entryPointRegistry.refList_ = [];
75 |
76 |
77 | /**
78 | * Monitors that should wrap all the entry points.
79 | * @type {!Array<!goog.debug.EntryPointMonitor>}
80 | * @private
81 | */
82 | goog.debug.entryPointRegistry.monitors_ = [];
83 |
84 |
85 | /**
86 | * Whether goog.debug.entryPointRegistry.monitorAll has ever been called.
87 | * Checking this allows the compiler to optimize out the registrations.
88 | * @type {boolean}
89 | * @private
90 | */
91 | goog.debug.entryPointRegistry.monitorsMayExist_ = false;
92 |
93 |
94 | /**
95 | * Register an entry point with this module.
96 | *
97 | * The entry point will be instrumented when a monitor is passed to
98 | * goog.debug.entryPointRegistry.monitorAll. If this has already occurred, the
99 | * entry point is instrumented immediately.
100 | *
101 | * @param {function(!Function)} callback A callback function which is called
102 | * with a transforming function to instrument the entry point. The callback
103 | * is responsible for wrapping the relevant entry point with the
104 | * transforming function.
105 | */
106 | goog.debug.entryPointRegistry.register = function(callback) {
107 | // Don't use push(), so that this can be compiled out.
108 | goog.debug.entryPointRegistry.refList_[
109 | goog.debug.entryPointRegistry.refList_.length] = callback;
110 | // If no one calls monitorAll, this can be compiled out.
111 | if (goog.debug.entryPointRegistry.monitorsMayExist_) {
112 | var monitors = goog.debug.entryPointRegistry.monitors_;
113 | for (var i = 0; i < monitors.length; i++) {
114 | callback(goog.bind(monitors[i].wrap, monitors[i]));
115 | }
116 | }
117 | };
118 |
119 |
120 | /**
121 | * Configures a monitor to wrap all entry points.
122 | *
123 | * Entry points that have already been registered are immediately wrapped by
124 | * the monitor. When an entry point is registered in the future, it will also
125 | * be wrapped by the monitor when it is registered.
126 | *
127 | * @param {!goog.debug.EntryPointMonitor} monitor An entry point monitor.
128 | */
129 | goog.debug.entryPointRegistry.monitorAll = function(monitor) {
130 | goog.debug.entryPointRegistry.monitorsMayExist_ = true;
131 | var transformer = goog.bind(monitor.wrap, monitor);
132 | for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
133 | goog.debug.entryPointRegistry.refList_[i](transformer);
134 | }
135 | goog.debug.entryPointRegistry.monitors_.push(monitor);
136 | };
137 |
138 |
139 | /**
140 | * Try to unmonitor all the entry points that have already been registered. If
141 | * an entry point is registered in the future, it will not be wrapped by the
142 | * monitor when it is registered. Note that this may fail if the entry points
143 | * have additional wrapping.
144 | *
145 | * @param {!goog.debug.EntryPointMonitor} monitor The last monitor to wrap
146 | * the entry points.
147 | * @throws {Error} If the monitor is not the most recently configured monitor.
148 | */
149 | goog.debug.entryPointRegistry.unmonitorAllIfPossible = function(monitor) {
150 | var monitors = goog.debug.entryPointRegistry.monitors_;
151 | goog.asserts.assert(monitor == monitors[monitors.length - 1],
152 | 'Only the most recent monitor can be unwrapped.');
153 | var transformer = goog.bind(monitor.unwrap, monitor);
154 | for (var i = 0; i < goog.debug.entryPointRegistry.refList_.length; i++) {
155 | goog.debug.entryPointRegistry.refList_[i](transformer);
156 | }
157 | monitors.length--;
158 | };