HeapSnapshotLoader.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * Copyright (C) 2012 Google Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions are
  6. * met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above
  11. * copyright notice, this list of conditions and the following disclaimer
  12. * in the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Google Inc. nor the names of its
  15. * contributors may be used to endorse or promote products derived from
  16. * this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. */
  30. /**
  31. * @constructor
  32. * @param{WebInspector.HeapSnapshotWorkerDispatcher} dispatcher
  33. * @implements {WebInspector.OutputStream}
  34. */
  35. WebInspector.HeapSnapshotLoader = function(dispatcher)
  36. {
  37. this._reset();
  38. this._progress = new WebInspector.HeapSnapshotProgress(dispatcher);
  39. }
  40. WebInspector.HeapSnapshotLoader.prototype = {
  41. dispose: function()
  42. {
  43. this._reset();
  44. },
  45. _reset: function()
  46. {
  47. this._json = "";
  48. this._state = "find-snapshot-info";
  49. this._snapshot = {};
  50. },
  51. close: function()
  52. {
  53. if (this._json)
  54. this._parseStringsArray();
  55. },
  56. buildSnapshot: function(constructorName)
  57. {
  58. this._progress.updateStatus("Processing snapshot\u2026");
  59. var constructor = WebInspector[constructorName];
  60. var result = new constructor(this._snapshot, this._progress);
  61. this._reset();
  62. return result;
  63. },
  64. _parseUintArray: function()
  65. {
  66. var index = 0;
  67. var char0 = "0".charCodeAt(0), char9 = "9".charCodeAt(0), closingBracket = "]".charCodeAt(0);
  68. var length = this._json.length;
  69. while (true) {
  70. while (index < length) {
  71. var code = this._json.charCodeAt(index);
  72. if (char0 <= code && code <= char9)
  73. break;
  74. else if (code === closingBracket) {
  75. this._json = this._json.slice(index + 1);
  76. return false;
  77. }
  78. ++index;
  79. }
  80. if (index === length) {
  81. this._json = "";
  82. return true;
  83. }
  84. var nextNumber = 0;
  85. var startIndex = index;
  86. while (index < length) {
  87. var code = this._json.charCodeAt(index);
  88. if (char0 > code || code > char9)
  89. break;
  90. nextNumber *= 10;
  91. nextNumber += (code - char0);
  92. ++index;
  93. }
  94. if (index === length) {
  95. this._json = this._json.slice(startIndex);
  96. return true;
  97. }
  98. this._array[this._arrayIndex++] = nextNumber;
  99. }
  100. },
  101. _parseStringsArray: function()
  102. {
  103. this._progress.updateStatus("Parsing strings\u2026");
  104. var closingBracketIndex = this._json.lastIndexOf("]");
  105. if (closingBracketIndex === -1)
  106. throw new Error("Incomplete JSON");
  107. this._json = this._json.slice(0, closingBracketIndex + 1);
  108. this._snapshot.strings = JSON.parse(this._json);
  109. },
  110. /**
  111. * @param {string} chunk
  112. */
  113. write: function(chunk)
  114. {
  115. this._json += chunk;
  116. switch (this._state) {
  117. case "find-snapshot-info": {
  118. var snapshotToken = "\"snapshot\"";
  119. var snapshotTokenIndex = this._json.indexOf(snapshotToken);
  120. if (snapshotTokenIndex === -1)
  121. throw new Error("Snapshot token not found");
  122. this._json = this._json.slice(snapshotTokenIndex + snapshotToken.length + 1);
  123. this._state = "parse-snapshot-info";
  124. this._progress.updateStatus("Loading snapshot info\u2026");
  125. }
  126. case "parse-snapshot-info": {
  127. var closingBracketIndex = WebInspector.findBalancedCurlyBrackets(this._json);
  128. if (closingBracketIndex === -1)
  129. return;
  130. this._snapshot.snapshot = /** @type {HeapSnapshotHeader} */ (JSON.parse(this._json.slice(0, closingBracketIndex)));
  131. this._json = this._json.slice(closingBracketIndex);
  132. this._state = "find-nodes";
  133. }
  134. case "find-nodes": {
  135. var nodesToken = "\"nodes\"";
  136. var nodesTokenIndex = this._json.indexOf(nodesToken);
  137. if (nodesTokenIndex === -1)
  138. return;
  139. var bracketIndex = this._json.indexOf("[", nodesTokenIndex);
  140. if (bracketIndex === -1)
  141. return;
  142. this._json = this._json.slice(bracketIndex + 1);
  143. var node_fields_count = this._snapshot.snapshot.meta.node_fields.length;
  144. var nodes_length = this._snapshot.snapshot.node_count * node_fields_count;
  145. this._array = new Uint32Array(nodes_length);
  146. this._arrayIndex = 0;
  147. this._state = "parse-nodes";
  148. }
  149. case "parse-nodes": {
  150. var hasMoreData = this._parseUintArray();
  151. this._progress.updateProgress("Loading nodes\u2026 %d\%", this._arrayIndex, this._array.length);
  152. if (hasMoreData)
  153. return;
  154. this._snapshot.nodes = this._array;
  155. this._state = "find-edges";
  156. this._array = null;
  157. }
  158. case "find-edges": {
  159. var edgesToken = "\"edges\"";
  160. var edgesTokenIndex = this._json.indexOf(edgesToken);
  161. if (edgesTokenIndex === -1)
  162. return;
  163. var bracketIndex = this._json.indexOf("[", edgesTokenIndex);
  164. if (bracketIndex === -1)
  165. return;
  166. this._json = this._json.slice(bracketIndex + 1);
  167. var edge_fields_count = this._snapshot.snapshot.meta.edge_fields.length;
  168. var edges_length = this._snapshot.snapshot.edge_count * edge_fields_count;
  169. this._array = new Uint32Array(edges_length);
  170. this._arrayIndex = 0;
  171. this._state = "parse-edges";
  172. }
  173. case "parse-edges": {
  174. var hasMoreData = this._parseUintArray();
  175. this._progress.updateProgress("Loading edges\u2026 %d\%", this._arrayIndex, this._array.length);
  176. if (hasMoreData)
  177. return;
  178. this._snapshot.edges = this._array;
  179. this._array = null;
  180. this._state = "find-strings";
  181. this._progress.updateStatus("Loading strings\u2026");
  182. }
  183. case "find-strings": {
  184. var stringsToken = "\"strings\"";
  185. var stringsTokenIndex = this._json.indexOf(stringsToken);
  186. if (stringsTokenIndex === -1)
  187. return;
  188. var bracketIndex = this._json.indexOf("[", stringsTokenIndex);
  189. if (bracketIndex === -1)
  190. return;
  191. this._json = this._json.slice(bracketIndex);
  192. this._state = "accumulate-strings";
  193. break;
  194. }
  195. case "accumulate-strings":
  196. break;
  197. }
  198. }
  199. };