2 * Copyright (C) 2010 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 var DebuggerScript = {};
35 DebuggerScript.PauseOnExceptionsState = {
36 DontPauseOnExceptions : 0,
37 PauseOnAllExceptions : 1,
38 PauseOnUncaughtExceptions: 2
41 DebuggerScript._pauseOnExceptionsState = DebuggerScript.PauseOnExceptionsState.DontPauseOnExceptions;
42 Debug.clearBreakOnException();
43 Debug.clearBreakOnUncaughtException();
45 DebuggerScript.getAfterCompileScript = function(eventData)
47 return DebuggerScript._formatScript(eventData.script_.script_);
50 DebuggerScript.getWorkerScripts = function()
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));
65 DebuggerScript.getFunctionScopes = function(fun)
67 var mirror = MakeMirror(fun);
68 var count = mirror.scopeCount();
72 for (var i = 0; i < count; i++) {
73 var scopeMirror = mirror.scope(i);
75 type: scopeMirror.scopeType(),
76 object: DebuggerScript._buildScopeObject(scopeMirror)
82 DebuggerScript.getInternalProperties = function(value)
84 var properties = ObjectMirror.GetInternalProperties(value);
86 for (var i = 0; i < properties.length; i++) {
87 var mirror = properties[i];
90 value: mirror.value().value()
96 DebuggerScript.setFunctionVariableValue = function(functionValue, scopeIndex, variableName, newValue)
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);
104 DebuggerScript._setScopeVariableValue = function(scopeHolder, scopeIndex, variableName, newValue)
106 var scopeMirror = scopeHolder.scope(scopeIndex);
108 throw new Error("Incorrect scope index");
109 scopeMirror.setVariableValue(variableName, newValue);
113 DebuggerScript.getScripts = function(contextData)
119 var comma = contextData.indexOf(",");
122 // Context data is a string in the following format:
123 // ("page"|"injected")","<page id>
124 var idSuffix = contextData.substring(comma); // including the comma
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));
135 DebuggerScript._formatScript = function(script)
137 var lineEnds = script.line_ends;
138 var lineCount = lineEnds.length;
139 var endLine = script.line_offset + lineCount - 1;
141 // V8 will not count last line if script source ends with \n.
142 if (script.source[script.source.length - 1] === '\n') {
147 endColumn = script.source.length + script.column_offset;
149 endColumn = script.source.length - (lineEnds[lineCount - 2] + 1);
154 name: script.nameOrSourceURL(),
155 source: script.source,
156 startLine: script.line_offset,
157 startColumn: script.column_offset,
159 endColumn: endColumn,
160 isContentScript: !!script.context_data && script.context_data.indexOf("injected") == 0
164 DebuggerScript.setBreakpoint = function(execState, info)
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);
169 var locations = Debug.findBreakPointActualLocations(breakId);
170 if (!locations.length)
172 info.lineNumber = locations[0].line;
173 info.columnNumber = locations[0].column;
174 return breakId.toString();
177 DebuggerScript.removeBreakpoint = function(execState, info)
179 Debug.findBreakPoint(info.breakpointId, true);
182 DebuggerScript.pauseOnExceptionsState = function()
184 return DebuggerScript._pauseOnExceptionsState;
187 DebuggerScript.setPauseOnExceptionsState = function(newState)
189 DebuggerScript._pauseOnExceptionsState = newState;
191 if (DebuggerScript.PauseOnExceptionsState.PauseOnAllExceptions === newState)
192 Debug.setBreakOnException();
194 Debug.clearBreakOnException();
196 if (DebuggerScript.PauseOnExceptionsState.PauseOnUncaughtExceptions === newState)
197 Debug.setBreakOnUncaughtException();
199 Debug.clearBreakOnUncaughtException();
202 DebuggerScript.currentCallFrame = function(execState, maximumLimit)
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);
215 DebuggerScript.stepIntoStatement = function(execState)
217 execState.prepareStep(Debug.StepAction.StepIn, 1);
220 DebuggerScript.stepOverStatement = function(execState, callFrame)
222 var frameMirror = callFrame ? callFrame.frameMirror : undefined;
223 execState.prepareStep(Debug.StepAction.StepNext, 1, frameMirror);
226 DebuggerScript.stepOutOfFunction = function(execState, callFrame)
228 var frameMirror = callFrame ? callFrame.frameMirror : undefined;
229 execState.prepareStep(Debug.StepAction.StepOut, 1, frameMirror);
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)
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];
247 throw("Script not found");
251 var result = Debug.LiveEdit.SetScriptSource(scriptToEdit, newSource, preview, changeLog);
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)];
265 DebuggerScript.clearBreakpoints = function(execState, info)
267 Debug.clearAllBreakPoints();
270 DebuggerScript.setBreakpointsActivated = function(execState, info)
272 Debug.debuggerFlags().breakPointsActive.setValue(info.enabled);
275 DebuggerScript.getScriptSource = function(eventData)
277 return eventData.script().source();
280 DebuggerScript.setScriptSource = function(eventData, source)
282 if (eventData.script().data() === "injected-script")
284 eventData.script().setSource(source);
287 DebuggerScript.getScriptName = function(eventData)
289 return eventData.script().script_.nameOrSourceURL();
292 DebuggerScript.getBreakpointNumbers = function(eventData)
294 var breakpoints = eventData.breakPointsHit();
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());
307 DebuggerScript.isEvalCompilation = function(eventData)
309 var script = eventData.script();
310 return (script.compilationType() === Debug.ScriptCompilationType.Eval);
313 DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror, callerFrame)
315 // Get function name and display name.
319 funcMirror = frameMirror.func();
321 var valueMirror = funcMirror.property("displayName").value();
322 if (valueMirror && valueMirror.isString())
323 displayName = valueMirror.value();
329 functionName = displayName || funcMirror.name() || funcMirror.inferredName();
332 var script = funcMirror.script();
333 var sourceID = script && script.id();
336 var location = frameMirror.sourceLocation();
339 var thisObject = frameMirror.details_.receiver();
341 var isAtReturn = !!frameMirror.details_.isAtReturn();
342 var returnValue = isAtReturn ? frameMirror.details_.returnValue() : undefined;
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));
352 function evaluate(expression)
354 return frameMirror.evaluate(expression, false).value();
359 return Debug.LiveEdit.RestartFrame(frameMirror);
362 function setVariableValue(scopeNumber, variableName, newValue)
364 return DebuggerScript._setScopeVariableValue(frameMirror, scopeNumber, variableName, newValue);
367 function stepInPositions()
369 var stepInPositionsV8 = frameMirror.stepInPositions();
370 var stepInPositionsProtocol;
371 if (stepInPositionsV8) {
372 stepInPositionsProtocol = [];
373 var script = frameMirror.func().script();
375 var scriptId = String(script.id());
376 for (var i = 0; i < stepInPositionsV8.length; i++) {
379 lineNumber: stepInPositionsV8[i].position.line,
380 columnNumber: stepInPositionsV8[i].position.column
382 stepInPositionsProtocol.push(item);
386 return JSON.stringify(stepInPositionsProtocol);
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,
400 "setVariableValue": setVariableValue,
401 "stepInPositions": stepInPositions,
402 "isAtReturn": isAtReturn,
403 "returnValue": returnValue,
404 "frameMirror": frameMirror
408 DebuggerScript._buildScopeObject = function(scopeMirror) {
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.
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_;
429 case ScopeType.Global:
431 scopeObject = scopeMirror.details_.object();
433 case ScopeType.Block:
434 // Unsupported yet. Mustn't be reachable.
440 return DebuggerScript;