codemap.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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. * Constructs a mapper that maps addresses into code entries.
  29. *
  30. * @constructor
  31. */
  32. function CodeMap() {
  33. /**
  34. * Dynamic code entries. Used for JIT compiled code.
  35. */
  36. this.dynamics_ = new SplayTree();
  37. /**
  38. * Name generator for entries having duplicate names.
  39. */
  40. this.dynamicsNameGen_ = new CodeMap.NameGenerator();
  41. /**
  42. * Static code entries. Used for statically compiled code.
  43. */
  44. this.statics_ = new SplayTree();
  45. /**
  46. * Libraries entries. Used for the whole static code libraries.
  47. */
  48. this.libraries_ = new SplayTree();
  49. /**
  50. * Map of memory pages occupied with static code.
  51. */
  52. this.pages_ = [];
  53. };
  54. /**
  55. * The number of alignment bits in a page address.
  56. */
  57. CodeMap.PAGE_ALIGNMENT = 12;
  58. /**
  59. * Page size in bytes.
  60. */
  61. CodeMap.PAGE_SIZE =
  62. 1 << CodeMap.PAGE_ALIGNMENT;
  63. /**
  64. * Adds a dynamic (i.e. moveable and discardable) code entry.
  65. *
  66. * @param {number} start The starting address.
  67. * @param {CodeMap.CodeEntry} codeEntry Code entry object.
  68. */
  69. CodeMap.prototype.addCode = function(start, codeEntry) {
  70. this.deleteAllCoveredNodes_(this.dynamics_, start, start + codeEntry.size);
  71. this.dynamics_.insert(start, codeEntry);
  72. };
  73. /**
  74. * Moves a dynamic code entry. Throws an exception if there is no dynamic
  75. * code entry with the specified starting address.
  76. *
  77. * @param {number} from The starting address of the entry being moved.
  78. * @param {number} to The destination address.
  79. */
  80. CodeMap.prototype.moveCode = function(from, to) {
  81. var removedNode = this.dynamics_.remove(from);
  82. this.deleteAllCoveredNodes_(this.dynamics_, to, to + removedNode.value.size);
  83. this.dynamics_.insert(to, removedNode.value);
  84. };
  85. /**
  86. * Discards a dynamic code entry. Throws an exception if there is no dynamic
  87. * code entry with the specified starting address.
  88. *
  89. * @param {number} start The starting address of the entry being deleted.
  90. */
  91. CodeMap.prototype.deleteCode = function(start) {
  92. var removedNode = this.dynamics_.remove(start);
  93. };
  94. /**
  95. * Adds a library entry.
  96. *
  97. * @param {number} start The starting address.
  98. * @param {CodeMap.CodeEntry} codeEntry Code entry object.
  99. */
  100. CodeMap.prototype.addLibrary = function(
  101. start, codeEntry) {
  102. this.markPages_(start, start + codeEntry.size);
  103. this.libraries_.insert(start, codeEntry);
  104. };
  105. /**
  106. * Adds a static code entry.
  107. *
  108. * @param {number} start The starting address.
  109. * @param {CodeMap.CodeEntry} codeEntry Code entry object.
  110. */
  111. CodeMap.prototype.addStaticCode = function(
  112. start, codeEntry) {
  113. this.statics_.insert(start, codeEntry);
  114. };
  115. /**
  116. * @private
  117. */
  118. CodeMap.prototype.markPages_ = function(start, end) {
  119. for (var addr = start; addr <= end;
  120. addr += CodeMap.PAGE_SIZE) {
  121. this.pages_[addr >>> CodeMap.PAGE_ALIGNMENT] = 1;
  122. }
  123. };
  124. /**
  125. * @private
  126. */
  127. CodeMap.prototype.deleteAllCoveredNodes_ = function(tree, start, end) {
  128. var to_delete = [];
  129. var addr = end - 1;
  130. while (addr >= start) {
  131. var node = tree.findGreatestLessThan(addr);
  132. if (!node) break;
  133. var start2 = node.key, end2 = start2 + node.value.size;
  134. if (start2 < end && start < end2) to_delete.push(start2);
  135. addr = start2 - 1;
  136. }
  137. for (var i = 0, l = to_delete.length; i < l; ++i) tree.remove(to_delete[i]);
  138. };
  139. /**
  140. * @private
  141. */
  142. CodeMap.prototype.isAddressBelongsTo_ = function(addr, node) {
  143. return addr >= node.key && addr < (node.key + node.value.size);
  144. };
  145. /**
  146. * @private
  147. */
  148. CodeMap.prototype.findInTree_ = function(tree, addr) {
  149. var node = tree.findGreatestLessThan(addr);
  150. return node && this.isAddressBelongsTo_(addr, node) ? node.value : null;
  151. };
  152. /**
  153. * Finds a code entry that contains the specified address. Both static and
  154. * dynamic code entries are considered.
  155. *
  156. * @param {number} addr Address.
  157. */
  158. CodeMap.prototype.findEntry = function(addr) {
  159. var pageAddr = addr >>> CodeMap.PAGE_ALIGNMENT;
  160. if (pageAddr in this.pages_) {
  161. // Static code entries can contain "holes" of unnamed code.
  162. // In this case, the whole library is assigned to this address.
  163. return this.findInTree_(this.statics_, addr) ||
  164. this.findInTree_(this.libraries_, addr);
  165. }
  166. var min = this.dynamics_.findMin();
  167. var max = this.dynamics_.findMax();
  168. if (max != null && addr < (max.key + max.value.size) && addr >= min.key) {
  169. var dynaEntry = this.findInTree_(this.dynamics_, addr);
  170. if (dynaEntry == null) return null;
  171. // Dedupe entry name.
  172. if (!dynaEntry.nameUpdated_) {
  173. dynaEntry.name = this.dynamicsNameGen_.getName(dynaEntry.name);
  174. dynaEntry.nameUpdated_ = true;
  175. }
  176. return dynaEntry;
  177. }
  178. return null;
  179. };
  180. /**
  181. * Returns a dynamic code entry using its starting address.
  182. *
  183. * @param {number} addr Address.
  184. */
  185. CodeMap.prototype.findDynamicEntryByStartAddress =
  186. function(addr) {
  187. var node = this.dynamics_.find(addr);
  188. return node ? node.value : null;
  189. };
  190. /**
  191. * Returns an array of all dynamic code entries.
  192. */
  193. CodeMap.prototype.getAllDynamicEntries = function() {
  194. return this.dynamics_.exportValues();
  195. };
  196. /**
  197. * Returns an array of pairs of all dynamic code entries and their addresses.
  198. */
  199. CodeMap.prototype.getAllDynamicEntriesWithAddresses = function() {
  200. return this.dynamics_.exportKeysAndValues();
  201. };
  202. /**
  203. * Returns an array of all static code entries.
  204. */
  205. CodeMap.prototype.getAllStaticEntries = function() {
  206. return this.statics_.exportValues();
  207. };
  208. /**
  209. * Returns an array of all libraries entries.
  210. */
  211. CodeMap.prototype.getAllLibrariesEntries = function() {
  212. return this.libraries_.exportValues();
  213. };
  214. /**
  215. * Creates a code entry object.
  216. *
  217. * @param {number} size Code entry size in bytes.
  218. * @param {string} opt_name Code entry name.
  219. * @constructor
  220. */
  221. CodeMap.CodeEntry = function(size, opt_name) {
  222. this.size = size;
  223. this.name = opt_name || '';
  224. this.nameUpdated_ = false;
  225. };
  226. CodeMap.CodeEntry.prototype.getName = function() {
  227. return this.name;
  228. };
  229. CodeMap.CodeEntry.prototype.toString = function() {
  230. return this.name + ': ' + this.size.toString(16);
  231. };
  232. CodeMap.NameGenerator = function() {
  233. this.knownNames_ = {};
  234. };
  235. CodeMap.NameGenerator.prototype.getName = function(name) {
  236. if (!(name in this.knownNames_)) {
  237. this.knownNames_[name] = 0;
  238. return name;
  239. }
  240. var count = ++this.knownNames_[name];
  241. return name + ' {' + count + '}';
  242. };