2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 * @param {!WebInspector.HeapSnapshotWorkerDispatcher} dispatcher
35 WebInspector.HeapSnapshotLoader = function(dispatcher)
38 this._progress = new WebInspector.HeapSnapshotProgress(dispatcher);
41 WebInspector.HeapSnapshotLoader.prototype = {
50 this._state = "find-snapshot-info";
57 this._parseStringsArray();
61 * @param {boolean} showHiddenData
62 * @return {!WebInspector.JSHeapSnapshot}
64 buildSnapshot: function(showHiddenData)
66 this._progress.updateStatus("Processing snapshot\u2026");
67 var result = new WebInspector.JSHeapSnapshot(this._snapshot, this._progress, showHiddenData);
72 _parseUintArray: function()
75 var char0 = "0".charCodeAt(0), char9 = "9".charCodeAt(0), closingBracket = "]".charCodeAt(0);
76 var length = this._json.length;
78 while (index < length) {
79 var code = this._json.charCodeAt(index);
80 if (char0 <= code && code <= char9)
82 else if (code === closingBracket) {
83 this._json = this._json.slice(index + 1);
88 if (index === length) {
93 var startIndex = index;
94 while (index < length) {
95 var code = this._json.charCodeAt(index);
96 if (char0 > code || code > char9)
99 nextNumber += (code - char0);
102 if (index === length) {
103 this._json = this._json.slice(startIndex);
106 this._array[this._arrayIndex++] = nextNumber;
110 _parseStringsArray: function()
112 this._progress.updateStatus("Parsing strings\u2026");
113 var closingBracketIndex = this._json.lastIndexOf("]");
114 if (closingBracketIndex === -1)
115 throw new Error("Incomplete JSON");
116 this._json = this._json.slice(0, closingBracketIndex + 1);
117 this._snapshot.strings = JSON.parse(this._json);
121 * @param {string} chunk
123 write: function(chunk)
127 switch (this._state) {
128 case "find-snapshot-info": {
129 var snapshotToken = "\"snapshot\"";
130 var snapshotTokenIndex = this._json.indexOf(snapshotToken);
131 if (snapshotTokenIndex === -1)
132 throw new Error("Snapshot token not found");
133 this._json = this._json.slice(snapshotTokenIndex + snapshotToken.length + 1);
134 this._state = "parse-snapshot-info";
135 this._progress.updateStatus("Loading snapshot info\u2026");
138 case "parse-snapshot-info": {
139 var closingBracketIndex = WebInspector.TextUtils.findBalancedCurlyBrackets(this._json);
140 if (closingBracketIndex === -1)
142 this._snapshot.snapshot = /** @type {!HeapSnapshotHeader} */ (JSON.parse(this._json.slice(0, closingBracketIndex)));
143 this._json = this._json.slice(closingBracketIndex);
144 this._state = "find-nodes";
148 var nodesToken = "\"nodes\"";
149 var nodesTokenIndex = this._json.indexOf(nodesToken);
150 if (nodesTokenIndex === -1)
152 var bracketIndex = this._json.indexOf("[", nodesTokenIndex);
153 if (bracketIndex === -1)
155 this._json = this._json.slice(bracketIndex + 1);
156 var node_fields_count = this._snapshot.snapshot.meta.node_fields.length;
157 var nodes_length = this._snapshot.snapshot.node_count * node_fields_count;
158 this._array = new Uint32Array(nodes_length);
159 this._arrayIndex = 0;
160 this._state = "parse-nodes";
163 case "parse-nodes": {
164 var hasMoreData = this._parseUintArray();
165 this._progress.updateProgress("Loading nodes\u2026 %d\%", this._arrayIndex, this._array.length);
168 this._snapshot.nodes = this._array;
169 this._state = "find-edges";
174 var edgesToken = "\"edges\"";
175 var edgesTokenIndex = this._json.indexOf(edgesToken);
176 if (edgesTokenIndex === -1)
178 var bracketIndex = this._json.indexOf("[", edgesTokenIndex);
179 if (bracketIndex === -1)
181 this._json = this._json.slice(bracketIndex + 1);
182 var edge_fields_count = this._snapshot.snapshot.meta.edge_fields.length;
183 var edges_length = this._snapshot.snapshot.edge_count * edge_fields_count;
184 this._array = new Uint32Array(edges_length);
185 this._arrayIndex = 0;
186 this._state = "parse-edges";
189 case "parse-edges": {
190 var hasMoreData = this._parseUintArray();
191 this._progress.updateProgress("Loading edges\u2026 %d\%", this._arrayIndex, this._array.length);
194 this._snapshot.edges = this._array;
196 // If there is allocation info parse it, otherwise jump straight to strings.
197 if (this._snapshot.snapshot.trace_function_count)
198 this._state = "find-trace-function-infos";
200 this._state = "find-strings";
203 case "find-trace-function-infos": {
204 var tracesToken = "\"trace_function_infos\"";
205 var tracesTokenIndex = this._json.indexOf(tracesToken);
206 if (tracesTokenIndex === -1)
208 var bracketIndex = this._json.indexOf("[", tracesTokenIndex);
209 if (bracketIndex === -1)
211 this._json = this._json.slice(bracketIndex + 1);
213 var trace_function_info_field_count = this._snapshot.snapshot.meta.trace_function_info_fields.length;
214 var trace_function_info_length = this._snapshot.snapshot.trace_function_count * trace_function_info_field_count;
215 this._array = new Uint32Array(trace_function_info_length);
216 this._arrayIndex = 0;
217 this._state = "parse-trace-function-infos";
220 case "parse-trace-function-infos": {
221 if (this._parseUintArray())
223 this._snapshot.trace_function_infos = this._array;
225 this._state = "find-trace-tree";
228 case "find-trace-tree": {
229 var tracesToken = "\"trace_tree\"";
230 var tracesTokenIndex = this._json.indexOf(tracesToken);
231 if (tracesTokenIndex === -1)
233 var bracketIndex = this._json.indexOf("[", tracesTokenIndex);
234 if (bracketIndex === -1)
236 this._json = this._json.slice(bracketIndex);
237 this._state = "parse-trace-tree";
240 case "parse-trace-tree": {
241 var stringsToken = "\"strings\"";
242 var stringsTokenIndex = this._json.indexOf(stringsToken);
243 if (stringsTokenIndex === -1)
245 var bracketIndex = this._json.lastIndexOf("]", stringsTokenIndex);
246 this._snapshot.trace_tree = JSON.parse(this._json.substring(0, bracketIndex + 1));
247 this._json = this._json.slice(bracketIndex);
248 this._state = "find-strings";
249 this._progress.updateStatus("Loading strings\u2026");
252 case "find-strings": {
253 var stringsToken = "\"strings\"";
254 var stringsTokenIndex = this._json.indexOf(stringsToken);
255 if (stringsTokenIndex === -1)
257 var bracketIndex = this._json.indexOf("[", stringsTokenIndex);
258 if (bracketIndex === -1)
260 this._json = this._json.slice(bracketIndex);
261 this._state = "accumulate-strings";
264 case "accumulate-strings":