OLD | NEW |
| (Empty) |
1 // Copyright 2009 the V8 project authors. All rights reserved. | |
2 // Redistribution and use in source and binary forms, with or without | |
3 // modification, are permitted provided that the following conditions are | |
4 // met: | |
5 // | |
6 // * Redistributions of source code must retain the above copyright | |
7 // notice, this list of conditions and the following disclaimer. | |
8 // * Redistributions in binary form must reproduce the above | |
9 // copyright notice, this list of conditions and the following | |
10 // disclaimer in the documentation and/or other materials provided | |
11 // with the distribution. | |
12 // * Neither the name of Google Inc. nor the names of its | |
13 // contributors may be used to endorse or promote products derived | |
14 // from this software without specific prior written permission. | |
15 // | |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
27 | |
28 | |
29 // Initlialize namespaces | |
30 var devtools = devtools || {}; | |
31 devtools.profiler = devtools.profiler || {}; | |
32 | |
33 | |
34 /** | |
35 * Constructs a mapper that maps addresses into code entries. | |
36 * | |
37 * @constructor | |
38 */ | |
39 devtools.profiler.CodeMap = function() { | |
40 /** | |
41 * Dynamic code entries. Used for JIT compiled code. | |
42 */ | |
43 this.dynamics_ = new goog.structs.SplayTree(); | |
44 | |
45 /** | |
46 * Name generator for entries having duplicate names. | |
47 */ | |
48 this.dynamicsNameGen_ = new devtools.profiler.CodeMap.NameGenerator(); | |
49 | |
50 /** | |
51 * Static code entries. Used for statically compiled code. | |
52 */ | |
53 this.statics_ = new goog.structs.SplayTree(); | |
54 | |
55 /** | |
56 * Libraries entries. Used for the whole static code libraries. | |
57 */ | |
58 this.libraries_ = new goog.structs.SplayTree(); | |
59 | |
60 /** | |
61 * Map of memory pages occupied with static code. | |
62 */ | |
63 this.pages_ = []; | |
64 }; | |
65 | |
66 | |
67 /** | |
68 * The number of alignment bits in a page address. | |
69 */ | |
70 devtools.profiler.CodeMap.PAGE_ALIGNMENT = 12; | |
71 | |
72 | |
73 /** | |
74 * Page size in bytes. | |
75 */ | |
76 devtools.profiler.CodeMap.PAGE_SIZE = | |
77 1 << devtools.profiler.CodeMap.PAGE_ALIGNMENT; | |
78 | |
79 | |
80 /** | |
81 * Adds a dynamic (i.e. moveable and discardable) code entry. | |
82 * | |
83 * @param {number} start The starting address. | |
84 * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object. | |
85 */ | |
86 devtools.profiler.CodeMap.prototype.addCode = function(start, codeEntry) { | |
87 this.dynamics_.insert(start, codeEntry); | |
88 }; | |
89 | |
90 | |
91 /** | |
92 * Moves a dynamic code entry. Throws an exception if there is no dynamic | |
93 * code entry with the specified starting address. | |
94 * | |
95 * @param {number} from The starting address of the entry being moved. | |
96 * @param {number} to The destination address. | |
97 */ | |
98 devtools.profiler.CodeMap.prototype.moveCode = function(from, to) { | |
99 var removedNode = this.dynamics_.remove(from); | |
100 this.dynamics_.insert(to, removedNode.value); | |
101 }; | |
102 | |
103 | |
104 /** | |
105 * Discards a dynamic code entry. Throws an exception if there is no dynamic | |
106 * code entry with the specified starting address. | |
107 * | |
108 * @param {number} start The starting address of the entry being deleted. | |
109 */ | |
110 devtools.profiler.CodeMap.prototype.deleteCode = function(start) { | |
111 var removedNode = this.dynamics_.remove(start); | |
112 }; | |
113 | |
114 | |
115 /** | |
116 * Adds a library entry. | |
117 * | |
118 * @param {number} start The starting address. | |
119 * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object. | |
120 */ | |
121 devtools.profiler.CodeMap.prototype.addLibrary = function( | |
122 start, codeEntry) { | |
123 this.markPages_(start, start + codeEntry.size); | |
124 this.libraries_.insert(start, codeEntry); | |
125 }; | |
126 | |
127 | |
128 /** | |
129 * Adds a static code entry. | |
130 * | |
131 * @param {number} start The starting address. | |
132 * @param {devtools.profiler.CodeMap.CodeEntry} codeEntry Code entry object. | |
133 */ | |
134 devtools.profiler.CodeMap.prototype.addStaticCode = function( | |
135 start, codeEntry) { | |
136 this.statics_.insert(start, codeEntry); | |
137 }; | |
138 | |
139 | |
140 /** | |
141 * @private | |
142 */ | |
143 devtools.profiler.CodeMap.prototype.markPages_ = function(start, end) { | |
144 for (var addr = start; addr <= end; | |
145 addr += devtools.profiler.CodeMap.PAGE_SIZE) { | |
146 this.pages_[addr >>> devtools.profiler.CodeMap.PAGE_ALIGNMENT] = 1; | |
147 } | |
148 }; | |
149 | |
150 | |
151 /** | |
152 * @private | |
153 */ | |
154 devtools.profiler.CodeMap.prototype.isAddressBelongsTo_ = function(addr, node) { | |
155 return addr >= node.key && addr < (node.key + node.value.size); | |
156 }; | |
157 | |
158 | |
159 /** | |
160 * @private | |
161 */ | |
162 devtools.profiler.CodeMap.prototype.findInTree_ = function(tree, addr) { | |
163 var node = tree.findGreatestLessThan(addr); | |
164 return node && this.isAddressBelongsTo_(addr, node) ? node.value : null; | |
165 }; | |
166 | |
167 | |
168 /** | |
169 * Finds a code entry that contains the specified address. Both static and | |
170 * dynamic code entries are considered. | |
171 * | |
172 * @param {number} addr Address. | |
173 */ | |
174 devtools.profiler.CodeMap.prototype.findEntry = function(addr) { | |
175 var pageAddr = addr >>> devtools.profiler.CodeMap.PAGE_ALIGNMENT; | |
176 if (pageAddr in this.pages_) { | |
177 // Static code entries can contain "holes" of unnamed code. | |
178 // In this case, the whole library is assigned to this address. | |
179 return this.findInTree_(this.statics_, addr) || | |
180 this.findInTree_(this.libraries_, addr); | |
181 } | |
182 var min = this.dynamics_.findMin(); | |
183 var max = this.dynamics_.findMax(); | |
184 if (max != null && addr < (max.key + max.value.size) && addr >= min.key) { | |
185 var dynaEntry = this.findInTree_(this.dynamics_, addr); | |
186 if (dynaEntry == null) return null; | |
187 // Dedupe entry name. | |
188 if (!dynaEntry.nameUpdated_) { | |
189 dynaEntry.name = this.dynamicsNameGen_.getName(dynaEntry.name); | |
190 dynaEntry.nameUpdated_ = true; | |
191 } | |
192 return dynaEntry; | |
193 } | |
194 return null; | |
195 }; | |
196 | |
197 | |
198 /** | |
199 * Returns an array of all dynamic code entries. | |
200 */ | |
201 devtools.profiler.CodeMap.prototype.getAllDynamicEntries = function() { | |
202 return this.dynamics_.exportValues(); | |
203 }; | |
204 | |
205 | |
206 /** | |
207 * Returns an array of all static code entries. | |
208 */ | |
209 devtools.profiler.CodeMap.prototype.getAllStaticEntries = function() { | |
210 return this.statics_.exportValues(); | |
211 }; | |
212 | |
213 | |
214 /** | |
215 * Returns an array of all libraries entries. | |
216 */ | |
217 devtools.profiler.CodeMap.prototype.getAllLibrariesEntries = function() { | |
218 return this.libraries_.exportValues(); | |
219 }; | |
220 | |
221 | |
222 /** | |
223 * Creates a code entry object. | |
224 * | |
225 * @param {number} size Code entry size in bytes. | |
226 * @param {string} opt_name Code entry name. | |
227 * @constructor | |
228 */ | |
229 devtools.profiler.CodeMap.CodeEntry = function(size, opt_name) { | |
230 this.size = size; | |
231 this.name = opt_name || ''; | |
232 this.nameUpdated_ = false; | |
233 }; | |
234 | |
235 | |
236 devtools.profiler.CodeMap.CodeEntry.prototype.getName = function() { | |
237 return this.name; | |
238 }; | |
239 | |
240 | |
241 devtools.profiler.CodeMap.CodeEntry.prototype.toString = function() { | |
242 return this.name + ': ' + this.size.toString(16); | |
243 }; | |
244 | |
245 | |
246 devtools.profiler.CodeMap.NameGenerator = function() { | |
247 this.knownNames_ = []; | |
248 }; | |
249 | |
250 | |
251 devtools.profiler.CodeMap.NameGenerator.prototype.getName = function(name) { | |
252 if (!(name in this.knownNames_)) { | |
253 this.knownNames_[name] = 0; | |
254 return name; | |
255 } | |
256 var count = ++this.knownNames_[name]; | |
257 return name + ' {' + count + '}'; | |
258 }; | |
OLD | NEW |