Upstream version 5.34.98.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / v8 / DebuggerScript.js
1 /*
2  * Copyright (C) 2010 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 (function () {
32
33 var DebuggerScript = {};
34
35 DebuggerScript.PauseOnExceptionsState = {
36     DontPauseOnExceptions : 0,
37     PauseOnAllExceptions : 1,
38     PauseOnUncaughtExceptions: 2
39 };
40
41 DebuggerScript._pauseOnExceptionsState = DebuggerScript.PauseOnExceptionsState.DontPauseOnExceptions;
42 Debug.clearBreakOnException();
43 Debug.clearBreakOnUncaughtException();
44
45 DebuggerScript.getAfterCompileScript = function(eventData)
46 {
47     return DebuggerScript._formatScript(eventData.script_.script_);
48 }
49
50 DebuggerScript.getWorkerScripts = function()
51 {
52     var result = [];
53     var scripts = Debug.scripts();
54     for (var i = 0; i < scripts.length; ++i) {
55         var script = scripts[i];
56         // Workers don't share same V8 heap now so there is no need to complicate stuff with
57         // the context id like we do to discriminate between scripts from different pages.
58         // However we need to filter out v8 native scripts.
59         if (script.context_data && script.context_data === "worker")
60             result.push(DebuggerScript._formatScript(script));
61     }
62     return result;
63 }
64
65 DebuggerScript.getFunctionScopes = function(fun)
66 {
67     var mirror = MakeMirror(fun);
68     var count = mirror.scopeCount();
69     if (count == 0)
70         return null;
71     var result = [];
72     for (var i = 0; i < count; i++) {
73         var scopeMirror = mirror.scope(i);
74         result[i] = {
75             type: scopeMirror.scopeType(),
76             object: DebuggerScript._buildScopeObject(scopeMirror)
77         };
78     }
79     return result;
80 }
81
82 DebuggerScript.getInternalProperties = function(value)
83 {
84     var properties = ObjectMirror.GetInternalProperties(value);
85     var result = [];
86     for (var i = 0; i < properties.length; i++) {
87         var mirror = properties[i];
88         result.push({
89             name: mirror.name(),
90             value: mirror.value().value()
91         });
92     }
93     return result;
94 }
95
96 DebuggerScript.setFunctionVariableValue = function(functionValue, scopeIndex, variableName, newValue)
97 {
98     var mirror = MakeMirror(functionValue);
99     if (!mirror.isFunction())
100         throw new Error("Function value has incorrect type");
101     return DebuggerScript._setScopeVariableValue(mirror, scopeIndex, variableName, newValue);
102 }
103
104 DebuggerScript._setScopeVariableValue = function(scopeHolder, scopeIndex, variableName, newValue)
105 {
106     var scopeMirror = scopeHolder.scope(scopeIndex);
107     if (!scopeMirror)
108         throw new Error("Incorrect scope index");
109     scopeMirror.setVariableValue(variableName, newValue);
110     return undefined;
111 }
112
113 DebuggerScript.getScripts = function(contextData)
114 {
115     var result = [];
116
117     if (!contextData)
118         return result;
119     var comma = contextData.indexOf(",");
120     if (comma === -1)
121         return result;
122     // Context data is a string in the following format:
123     // ("page"|"injected")","<page id>
124     var idSuffix = contextData.substring(comma); // including the comma
125
126     var scripts = Debug.scripts();
127     for (var i = 0; i < scripts.length; ++i) {
128         var script = scripts[i];
129         if (script.context_data && script.context_data.lastIndexOf(idSuffix) != -1)
130             result.push(DebuggerScript._formatScript(script));
131     }
132     return result;
133 }
134
135 DebuggerScript._formatScript = function(script)
136 {
137     var lineEnds = script.line_ends;
138     var lineCount = lineEnds.length;
139     var endLine = script.line_offset + lineCount - 1;
140     var endColumn;
141     // V8 will not count last line if script source ends with \n.
142     if (script.source[script.source.length - 1] === '\n') {
143         endLine += 1;
144         endColumn = 0;
145     } else {
146         if (lineCount === 1)
147             endColumn = script.source.length + script.column_offset;
148         else
149             endColumn = script.source.length - (lineEnds[lineCount - 2] + 1);
150     }
151
152     return {
153         id: script.id,
154         name: script.nameOrSourceURL(),
155         source: script.source,
156         startLine: script.line_offset,
157         startColumn: script.column_offset,
158         endLine: endLine,
159         endColumn: endColumn,
160         isContentScript: !!script.context_data && script.context_data.indexOf("injected") == 0
161     };
162 }
163
164 DebuggerScript.setBreakpoint = function(execState, info)
165 {
166     var positionAlignment = info.interstatementLocation ? Debug.BreakPositionAlignment.BreakPosition : Debug.BreakPositionAlignment.Statement;
167     var breakId = Debug.setScriptBreakPointById(info.sourceID, info.lineNumber, info.columnNumber, info.condition, undefined, positionAlignment);
168
169     var locations = Debug.findBreakPointActualLocations(breakId);
170     if (!locations.length)
171         return undefined;
172     info.lineNumber = locations[0].line;
173     info.columnNumber = locations[0].column;
174     return breakId.toString();
175 }
176
177 DebuggerScript.removeBreakpoint = function(execState, info)
178 {
179     Debug.findBreakPoint(info.breakpointId, true);
180 }
181
182 DebuggerScript.pauseOnExceptionsState = function()
183 {
184     return DebuggerScript._pauseOnExceptionsState;
185 }
186
187 DebuggerScript.setPauseOnExceptionsState = function(newState)
188 {
189     DebuggerScript._pauseOnExceptionsState = newState;
190
191     if (DebuggerScript.PauseOnExceptionsState.PauseOnAllExceptions === newState)
192         Debug.setBreakOnException();
193     else
194         Debug.clearBreakOnException();
195
196     if (DebuggerScript.PauseOnExceptionsState.PauseOnUncaughtExceptions === newState)
197         Debug.setBreakOnUncaughtException();
198     else
199         Debug.clearBreakOnUncaughtException();
200 }
201
202 DebuggerScript.currentCallFrame = function(execState, maximumLimit)
203 {
204     var frameCount = execState.frameCount();
205     if (maximumLimit >= 0 && maximumLimit < frameCount)
206         frameCount = maximumLimit;
207     var topFrame = undefined;
208     for (var i = frameCount - 1; i >= 0; i--) {
209         var frameMirror = execState.frame(i);
210         topFrame = DebuggerScript._frameMirrorToJSCallFrame(frameMirror, topFrame);
211     }
212     return topFrame;
213 }
214
215 DebuggerScript.stepIntoStatement = function(execState)
216 {
217     execState.prepareStep(Debug.StepAction.StepIn, 1);
218 }
219
220 DebuggerScript.stepOverStatement = function(execState, callFrame)
221 {
222     var frameMirror = callFrame ? callFrame.frameMirror : undefined;
223     execState.prepareStep(Debug.StepAction.StepNext, 1, frameMirror);
224 }
225
226 DebuggerScript.stepOutOfFunction = function(execState, callFrame)
227 {
228     var frameMirror = callFrame ? callFrame.frameMirror : undefined;
229     execState.prepareStep(Debug.StepAction.StepOut, 1, frameMirror);
230 }
231
232 // Returns array in form:
233 //      [ 0, <v8_result_report> ] in case of success
234 //   or [ 1, <general_error_message>, <compiler_message>, <line_number>, <column_number> ] in case of compile error, numbers are 1-based.
235 // or throws exception with message.
236 DebuggerScript.liveEditScriptSource = function(scriptId, newSource, preview)
237 {
238     var scripts = Debug.scripts();
239     var scriptToEdit = null;
240     for (var i = 0; i < scripts.length; i++) {
241         if (scripts[i].id == scriptId) {
242             scriptToEdit = scripts[i];
243             break;
244         }
245     }
246     if (!scriptToEdit)
247         throw("Script not found");
248
249     var changeLog = [];
250     try {
251         var result = Debug.LiveEdit.SetScriptSource(scriptToEdit, newSource, preview, changeLog);
252         return [0, result];
253     } catch (e) {
254         if (e instanceof Debug.LiveEdit.Failure && "details" in e) {
255             var details = e.details;
256             if (details.type === "liveedit_compile_error") {
257                 var startPosition = details.position.start;
258                 return [1, String(e), String(details.syntaxErrorMessage), Number(startPosition.line), Number(startPosition.column)];
259             }
260         }
261         throw e;
262     }
263 }
264
265 DebuggerScript.clearBreakpoints = function(execState, info)
266 {
267     Debug.clearAllBreakPoints();
268 }
269
270 DebuggerScript.setBreakpointsActivated = function(execState, info)
271 {
272     Debug.debuggerFlags().breakPointsActive.setValue(info.enabled);
273 }
274
275 DebuggerScript.getScriptSource = function(eventData)
276 {
277     return eventData.script().source();
278 }
279
280 DebuggerScript.setScriptSource = function(eventData, source)
281 {
282     if (eventData.script().data() === "injected-script")
283         return;
284     eventData.script().setSource(source);
285 }
286
287 DebuggerScript.getScriptName = function(eventData)
288 {
289     return eventData.script().script_.nameOrSourceURL();
290 }
291
292 DebuggerScript.getBreakpointNumbers = function(eventData)
293 {
294     var breakpoints = eventData.breakPointsHit();
295     var numbers = [];
296     if (!breakpoints)
297         return numbers;
298
299     for (var i = 0; i < breakpoints.length; i++) {
300         var breakpoint = breakpoints[i];
301         var scriptBreakPoint = breakpoint.script_break_point();
302         numbers.push(scriptBreakPoint ? scriptBreakPoint.number() : breakpoint.number());
303     }
304     return numbers;
305 }
306
307 DebuggerScript.isEvalCompilation = function(eventData)
308 {
309     var script = eventData.script();
310     return (script.compilationType() === Debug.ScriptCompilationType.Eval);
311 }
312
313 DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame)
314 {
315     // Get function name and display name.
316     var funcMirror;
317     var displayName;
318     try {
319         funcMirror = frameMirror.func();
320         if (funcMirror) {
321             var valueMirror = funcMirror.property("displayName").value();
322             if (valueMirror && valueMirror.isString())
323                 displayName = valueMirror.value();
324         }
325     } catch(e) {
326     }
327     var functionName;
328     if (funcMirror)
329         functionName = displayName || funcMirror.name() || funcMirror.inferredName();
330
331     // Get script ID.
332     var script = funcMirror.script();
333     var sourceID = script && script.id();
334
335     // Get location.
336     var location  = frameMirror.sourceLocation();
337
338     // Get this object.
339     var thisObject = frameMirror.details_.receiver();
340
341     var isAtReturn = !!frameMirror.details_.isAtReturn();
342     var returnValue = isAtReturn ? frameMirror.details_.returnValue() : undefined;
343
344     var scopeChain = [];
345     var scopeType = [];
346     for (var i = 0; i < frameMirror.scopeCount(); i++) {
347         var scopeMirror = frameMirror.scope(i);
348         scopeType.push(scopeMirror.scopeType());
349         scopeChain.push(DebuggerScript._buildScopeObject(scopeMirror));
350     }
351
352     function evaluate(expression)
353     {
354         return frameMirror.evaluate(expression, false).value();
355     }
356
357     function restart()
358     {
359         return Debug.LiveEdit.RestartFrame(frameMirror);
360     }
361
362     function setVariableValue(scopeNumber, variableName, newValue)
363     {
364         return DebuggerScript._setScopeVariableValue(frameMirror, scopeNumber, variableName, newValue);
365     }
366
367     function stepInPositions()
368     {
369         var stepInPositionsV8 = frameMirror.stepInPositions();
370         var stepInPositionsProtocol;
371         if (stepInPositionsV8) {
372             stepInPositionsProtocol = [];
373             var script = frameMirror.func().script();
374             if (script) {
375                 var scriptId = String(script.id());
376                 for (var i = 0; i < stepInPositionsV8.length; i++) {
377                     var item = {
378                         scriptId: scriptId,
379                         lineNumber: stepInPositionsV8[i].position.line,
380                         columnNumber: stepInPositionsV8[i].position.column
381                     };
382                     stepInPositionsProtocol.push(item);
383                 }
384             }
385         }
386         return JSON.stringify(stepInPositionsProtocol);
387     }
388
389     return {
390         "sourceID": sourceID,
391         "line": location ? location.line : 0,
392         "column": location ? location.column : 0,
393         "functionName": functionName,
394         "thisObject": thisObject,
395         "scopeChain": scopeChain,
396         "scopeType": scopeType,
397         "evaluate": evaluate,
398         "caller": callerFrame,
399         "restart": restart,
400         "setVariableValue": setVariableValue,
401         "stepInPositions": stepInPositions,
402         "isAtReturn": isAtReturn,
403         "returnValue": returnValue,
404         "frameMirror": frameMirror
405     };
406 }
407
408 DebuggerScript._buildScopeObject = function(scopeMirror) {
409     var scopeObject;
410     switch (scopeMirror.scopeType()) {
411     case ScopeType.Local:
412     case ScopeType.Closure:
413     case ScopeType.Catch:
414         // For transient objects we create a "persistent" copy that contains
415         // the same properties.
416         scopeObject = {};
417         // Reset scope object prototype to null so that the proto properties
418         // don't appear in the local scope section.
419         scopeObject.__proto__ = null;
420         var scopeObjectMirror = scopeMirror.scopeObject();
421         var properties = scopeObjectMirror.properties();
422         for (var j = 0; j < properties.length; j++) {
423             var name = properties[j].name();
424             if (name.charAt(0) === ".")
425                 continue; // Skip internal variables like ".arguments"
426             scopeObject[name] = properties[j].value_;
427         }
428         break;
429     case ScopeType.Global:
430     case ScopeType.With:
431         scopeObject = scopeMirror.details_.object();
432         break;
433     case ScopeType.Block:
434         // Unsupported yet. Mustn't be reachable.
435         break;
436     }
437     return scopeObject;
438 }
439
440 return DebuggerScript;
441 })();