Upstream version 7.35.144.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / profiler / heap_snapshot_worker / HeapSnapshotLoader.js
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 /**
32  * @constructor
33  * @param {!WebInspector.HeapSnapshotWorkerDispatcher} dispatcher
34  */
35 WebInspector.HeapSnapshotLoader = function(dispatcher)
36 {
37     this._reset();
38     this._progress = new WebInspector.HeapSnapshotProgress(dispatcher);
39 }
40
41 WebInspector.HeapSnapshotLoader.prototype = {
42     dispose: function()
43     {
44         this._reset();
45     },
46
47     _reset: function()
48     {
49         this._json = "";
50         this._state = "find-snapshot-info";
51         this._snapshot = {};
52     },
53
54     close: function()
55     {
56         if (this._json)
57             this._parseStringsArray();
58     },
59
60     /**
61      * @param {boolean} showHiddenData
62      * @return {!WebInspector.JSHeapSnapshot}
63      */
64     buildSnapshot: function(showHiddenData)
65     {
66         this._progress.updateStatus("Processing snapshot\u2026");
67         var result = new WebInspector.JSHeapSnapshot(this._snapshot, this._progress, showHiddenData);
68         this._reset();
69         return result;
70     },
71
72     _parseUintArray: function()
73     {
74         var index = 0;
75         var char0 = "0".charCodeAt(0), char9 = "9".charCodeAt(0), closingBracket = "]".charCodeAt(0);
76         var length = this._json.length;
77         while (true) {
78             while (index < length) {
79                 var code = this._json.charCodeAt(index);
80                 if (char0 <= code && code <= char9)
81                     break;
82                 else if (code === closingBracket) {
83                     this._json = this._json.slice(index + 1);
84                     return false;
85                 }
86                 ++index;
87             }
88             if (index === length) {
89                 this._json = "";
90                 return true;
91             }
92             var nextNumber = 0;
93             var startIndex = index;
94             while (index < length) {
95                 var code = this._json.charCodeAt(index);
96                 if (char0 > code || code > char9)
97                     break;
98                 nextNumber *= 10;
99                 nextNumber += (code - char0);
100                 ++index;
101             }
102             if (index === length) {
103                 this._json = this._json.slice(startIndex);
104                 return true;
105             }
106             this._array[this._arrayIndex++] = nextNumber;
107         }
108     },
109
110     _parseStringsArray: function()
111     {
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);
118     },
119
120     /**
121      * @param {string} chunk
122      */
123     write: function(chunk)
124     {
125         this._json += chunk;
126         while (true) {
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");
136                 break;
137             }
138             case "parse-snapshot-info": {
139                 var closingBracketIndex = WebInspector.TextUtils.findBalancedCurlyBrackets(this._json);
140                 if (closingBracketIndex === -1)
141                     return;
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";
145                 break;
146             }
147             case "find-nodes": {
148                 var nodesToken = "\"nodes\"";
149                 var nodesTokenIndex = this._json.indexOf(nodesToken);
150                 if (nodesTokenIndex === -1)
151                     return;
152                 var bracketIndex = this._json.indexOf("[", nodesTokenIndex);
153                 if (bracketIndex === -1)
154                     return;
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";
161                 break;
162             }
163             case "parse-nodes": {
164                 var hasMoreData = this._parseUintArray();
165                 this._progress.updateProgress("Loading nodes\u2026 %d\%", this._arrayIndex, this._array.length);
166                 if (hasMoreData)
167                     return;
168                 this._snapshot.nodes = this._array;
169                 this._state = "find-edges";
170                 this._array = null;
171                 break;
172             }
173             case "find-edges": {
174                 var edgesToken = "\"edges\"";
175                 var edgesTokenIndex = this._json.indexOf(edgesToken);
176                 if (edgesTokenIndex === -1)
177                     return;
178                 var bracketIndex = this._json.indexOf("[", edgesTokenIndex);
179                 if (bracketIndex === -1)
180                     return;
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";
187                 break;
188             }
189             case "parse-edges": {
190                 var hasMoreData = this._parseUintArray();
191                 this._progress.updateProgress("Loading edges\u2026 %d\%", this._arrayIndex, this._array.length);
192                 if (hasMoreData)
193                     return;
194                 this._snapshot.edges = this._array;
195                 this._array = null;
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";
199                 else
200                     this._state = "find-strings";
201                 break;
202             }
203             case "find-trace-function-infos": {
204                 var tracesToken = "\"trace_function_infos\"";
205                 var tracesTokenIndex = this._json.indexOf(tracesToken);
206                 if (tracesTokenIndex === -1)
207                     return;
208                 var bracketIndex = this._json.indexOf("[", tracesTokenIndex);
209                 if (bracketIndex === -1)
210                     return;
211                 this._json = this._json.slice(bracketIndex + 1);
212
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";
218                 break;
219             }
220             case "parse-trace-function-infos": {
221                 if (this._parseUintArray())
222                     return;
223                 this._snapshot.trace_function_infos = this._array;
224                 this._array = null;
225                 this._state = "find-trace-tree";
226                 break;
227             }
228             case "find-trace-tree": {
229                 var tracesToken = "\"trace_tree\"";
230                 var tracesTokenIndex = this._json.indexOf(tracesToken);
231                 if (tracesTokenIndex === -1)
232                     return;
233                 var bracketIndex = this._json.indexOf("[", tracesTokenIndex);
234                 if (bracketIndex === -1)
235                     return;
236                 this._json = this._json.slice(bracketIndex);
237                 this._state = "parse-trace-tree";
238                 break;
239             }
240             case "parse-trace-tree": {
241                 var stringsToken = "\"strings\"";
242                 var stringsTokenIndex = this._json.indexOf(stringsToken);
243                 if (stringsTokenIndex === -1)
244                     return;
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");
250                 break;
251             }
252             case "find-strings": {
253                 var stringsToken = "\"strings\"";
254                 var stringsTokenIndex = this._json.indexOf(stringsToken);
255                 if (stringsTokenIndex === -1)
256                     return;
257                 var bracketIndex = this._json.indexOf("[", stringsTokenIndex);
258                 if (bracketIndex === -1)
259                     return;
260                 this._json = this._json.slice(bracketIndex);
261                 this._state = "accumulate-strings";
262                 break;
263             }
264             case "accumulate-strings":
265                 return;
266             }
267         }
268     }
269 };