OLD | NEW |
| (Empty) |
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 "use strict"; | |
31 | |
32 (function () { | |
33 | |
34 var DebuggerScript = {}; | |
35 | |
36 /** @enum */ | |
37 DebuggerScript.PauseOnExceptionsState = { | |
38 DontPauseOnExceptions: 0, | |
39 PauseOnAllExceptions: 1, | |
40 PauseOnUncaughtExceptions: 2 | |
41 }; | |
42 | |
43 DebuggerScript._pauseOnExceptionsState = DebuggerScript.PauseOnExceptionsState.D
ontPauseOnExceptions; | |
44 Debug.clearBreakOnException(); | |
45 Debug.clearBreakOnUncaughtException(); | |
46 | |
47 /** | |
48 * @param {?CompileEvent} eventData | |
49 */ | |
50 DebuggerScript.getAfterCompileScript = function(eventData) | |
51 { | |
52 var script = eventData.script().value(); | |
53 if (!script.is_debugger_script) | |
54 return DebuggerScript._formatScript(eventData.script().value()); | |
55 return null; | |
56 } | |
57 | |
58 /** @type {!Map<!ScopeType, string>} */ | |
59 DebuggerScript._scopeTypeNames = new Map(); | |
60 DebuggerScript._scopeTypeNames.set(ScopeType.Global, "global"); | |
61 DebuggerScript._scopeTypeNames.set(ScopeType.Local, "local"); | |
62 DebuggerScript._scopeTypeNames.set(ScopeType.With, "with"); | |
63 DebuggerScript._scopeTypeNames.set(ScopeType.Closure, "closure"); | |
64 DebuggerScript._scopeTypeNames.set(ScopeType.Catch, "catch"); | |
65 DebuggerScript._scopeTypeNames.set(ScopeType.Block, "block"); | |
66 DebuggerScript._scopeTypeNames.set(ScopeType.Script, "script"); | |
67 | |
68 /** | |
69 * @param {function()} fun | |
70 * @return {?Array<!Scope>} | |
71 */ | |
72 DebuggerScript.getFunctionScopes = function(fun) | |
73 { | |
74 var mirror = MakeMirror(fun); | |
75 if (!mirror.isFunction()) | |
76 return null; | |
77 var functionMirror = /** @type {!FunctionMirror} */(mirror); | |
78 var count = functionMirror.scopeCount(); | |
79 if (count == 0) | |
80 return null; | |
81 var result = []; | |
82 for (var i = 0; i < count; i++) { | |
83 var scopeDetails = functionMirror.scope(i).details(); | |
84 var scopeObject = DebuggerScript._buildScopeObject(scopeDetails.type(),
scopeDetails.object()); | |
85 if (!scopeObject) | |
86 continue; | |
87 result.push({ | |
88 type: /** @type {string} */(DebuggerScript._scopeTypeNames.get(scope
Details.type())), | |
89 object: scopeObject, | |
90 name: scopeDetails.name() || "" | |
91 }); | |
92 } | |
93 return result; | |
94 } | |
95 | |
96 /** | |
97 * @param {Object} object | |
98 * @return {?RawLocation} | |
99 */ | |
100 DebuggerScript.getGeneratorObjectLocation = function(object) | |
101 { | |
102 var mirror = MakeMirror(object, true /* transient */); | |
103 if (!mirror.isGenerator()) | |
104 return null; | |
105 var generatorMirror = /** @type {!GeneratorMirror} */(mirror); | |
106 var funcMirror = generatorMirror.func(); | |
107 if (!funcMirror.resolved()) | |
108 return null; | |
109 var location = generatorMirror.sourceLocation() || funcMirror.sourceLocation
(); | |
110 var script = funcMirror.script(); | |
111 if (script && location) { | |
112 return { | |
113 scriptId: "" + script.id(), | |
114 lineNumber: location.line, | |
115 columnNumber: location.column | |
116 }; | |
117 } | |
118 return null; | |
119 } | |
120 | |
121 /** | |
122 * @param {Object} object | |
123 * @return {!Array<!{value: *}>|undefined} | |
124 */ | |
125 DebuggerScript.getCollectionEntries = function(object) | |
126 { | |
127 var mirror = MakeMirror(object, true /* transient */); | |
128 if (mirror.isMap()) | |
129 return /** @type {!MapMirror} */(mirror).entries(); | |
130 if (mirror.isSet() || mirror.isIterator()) { | |
131 var result = []; | |
132 var values = mirror.isSet() ? /** @type {!SetMirror} */(mirror).values()
: /** @type {!IteratorMirror} */(mirror).preview(); | |
133 for (var i = 0; i < values.length; ++i) | |
134 result.push({ value: values[i] }); | |
135 return result; | |
136 } | |
137 } | |
138 | |
139 /** | |
140 * @param {string|undefined} contextData | |
141 * @return {number} | |
142 */ | |
143 DebuggerScript._executionContextId = function(contextData) | |
144 { | |
145 if (!contextData) | |
146 return 0; | |
147 var match = contextData.match(/^[^,]*,([^,]*),.*$/); | |
148 if (!match) | |
149 return 0; | |
150 return parseInt(match[1], 10) || 0; | |
151 } | |
152 | |
153 /** | |
154 * @param {string|undefined} contextData | |
155 * @return {string} | |
156 */ | |
157 DebuggerScript._executionContextAuxData = function(contextData) | |
158 { | |
159 if (!contextData) | |
160 return ""; | |
161 var match = contextData.match(/^[^,]*,[^,]*,(.*)$/); | |
162 return match ? match[1] : ""; | |
163 } | |
164 | |
165 /** | |
166 * @param {string} contextGroupId | |
167 * @return {!Array<!FormattedScript>} | |
168 */ | |
169 DebuggerScript.getScripts = function(contextGroupId) | |
170 { | |
171 var result = []; | |
172 var scripts = Debug.scripts(); | |
173 var contextDataPrefix = null; | |
174 if (contextGroupId) | |
175 contextDataPrefix = contextGroupId + ","; | |
176 for (var i = 0; i < scripts.length; ++i) { | |
177 var script = scripts[i]; | |
178 if (contextDataPrefix) { | |
179 if (!script.context_data) | |
180 continue; | |
181 // Context data is a string in the following format: | |
182 // <contextGroupId>,<contextId>,<auxData> | |
183 if (script.context_data.indexOf(contextDataPrefix) !== 0) | |
184 continue; | |
185 } | |
186 if (script.is_debugger_script) | |
187 continue; | |
188 result.push(DebuggerScript._formatScript(script)); | |
189 } | |
190 return result; | |
191 } | |
192 | |
193 /** | |
194 * @param {!Script} script | |
195 * @return {!FormattedScript} | |
196 */ | |
197 DebuggerScript._formatScript = function(script) | |
198 { | |
199 var lineEnds = script.line_ends; | |
200 var lineCount = lineEnds.length; | |
201 var endLine = script.line_offset + lineCount - 1; | |
202 var endColumn; | |
203 // V8 will not count last line if script source ends with \n. | |
204 if (script.source[script.source.length - 1] === '\n') { | |
205 endLine += 1; | |
206 endColumn = 0; | |
207 } else { | |
208 if (lineCount === 1) | |
209 endColumn = script.source.length + script.column_offset; | |
210 else | |
211 endColumn = script.source.length - (lineEnds[lineCount - 2] + 1); | |
212 } | |
213 return { | |
214 id: script.id, | |
215 name: script.nameOrSourceURL(), | |
216 sourceURL: script.source_url, | |
217 sourceMappingURL: script.source_mapping_url, | |
218 source: script.source, | |
219 startLine: script.line_offset, | |
220 startColumn: script.column_offset, | |
221 endLine: endLine, | |
222 endColumn: endColumn, | |
223 executionContextId: DebuggerScript._executionContextId(script.context_da
ta), | |
224 // Note that we cannot derive aux data from context id because of compil
ation cache. | |
225 executionContextAuxData: DebuggerScript._executionContextAuxData(script.
context_data) | |
226 }; | |
227 } | |
228 | |
229 /** | |
230 * @param {!ExecutionState} execState | |
231 * @param {!BreakpointInfo} info | |
232 * @return {string|undefined} | |
233 */ | |
234 DebuggerScript.setBreakpoint = function(execState, info) | |
235 { | |
236 var breakId = Debug.setScriptBreakPointById(info.sourceID, info.lineNumber,
info.columnNumber, info.condition, undefined, Debug.BreakPositionAlignment.State
ment); | |
237 var locations = Debug.findBreakPointActualLocations(breakId); | |
238 if (!locations.length) | |
239 return undefined; | |
240 info.lineNumber = locations[0].line; | |
241 info.columnNumber = locations[0].column; | |
242 return breakId.toString(); | |
243 } | |
244 | |
245 /** | |
246 * @param {!ExecutionState} execState | |
247 * @param {!{breakpointId: number}} info | |
248 */ | |
249 DebuggerScript.removeBreakpoint = function(execState, info) | |
250 { | |
251 Debug.findBreakPoint(info.breakpointId, true); | |
252 } | |
253 | |
254 /** | |
255 * @return {number} | |
256 */ | |
257 DebuggerScript.pauseOnExceptionsState = function() | |
258 { | |
259 return DebuggerScript._pauseOnExceptionsState; | |
260 } | |
261 | |
262 /** | |
263 * @param {number} newState | |
264 */ | |
265 DebuggerScript.setPauseOnExceptionsState = function(newState) | |
266 { | |
267 DebuggerScript._pauseOnExceptionsState = newState; | |
268 | |
269 if (DebuggerScript.PauseOnExceptionsState.PauseOnAllExceptions === newState) | |
270 Debug.setBreakOnException(); | |
271 else | |
272 Debug.clearBreakOnException(); | |
273 | |
274 if (DebuggerScript.PauseOnExceptionsState.PauseOnUncaughtExceptions === newS
tate) | |
275 Debug.setBreakOnUncaughtException(); | |
276 else | |
277 Debug.clearBreakOnUncaughtException(); | |
278 } | |
279 | |
280 /** | |
281 * @param {!ExecutionState} execState | |
282 * @param {number} limit | |
283 * @return {!Array<!JavaScriptCallFrame>} | |
284 */ | |
285 DebuggerScript.currentCallFrames = function(execState, limit) | |
286 { | |
287 var frames = []; | |
288 for (var i = 0; i < execState.frameCount() && (!limit || i < limit); ++i) | |
289 frames.push(DebuggerScript._frameMirrorToJSCallFrame(execState.frame(i))
); | |
290 return frames; | |
291 } | |
292 | |
293 /** | |
294 * @param {!ExecutionState} execState | |
295 */ | |
296 DebuggerScript.stepIntoStatement = function(execState) | |
297 { | |
298 execState.prepareStep(Debug.StepAction.StepIn); | |
299 } | |
300 | |
301 /** | |
302 * @param {!ExecutionState} execState | |
303 */ | |
304 DebuggerScript.stepFrameStatement = function(execState) | |
305 { | |
306 execState.prepareStep(Debug.StepAction.StepFrame); | |
307 } | |
308 | |
309 /** | |
310 * @param {!ExecutionState} execState | |
311 */ | |
312 DebuggerScript.stepOverStatement = function(execState) | |
313 { | |
314 execState.prepareStep(Debug.StepAction.StepNext); | |
315 } | |
316 | |
317 /** | |
318 * @param {!ExecutionState} execState | |
319 */ | |
320 DebuggerScript.stepOutOfFunction = function(execState) | |
321 { | |
322 execState.prepareStep(Debug.StepAction.StepOut); | |
323 } | |
324 | |
325 DebuggerScript.clearStepping = function() | |
326 { | |
327 Debug.clearStepping(); | |
328 } | |
329 | |
330 // Returns array in form: | |
331 // [ 0, <v8_result_report> ] in case of success | |
332 // or [ 1, <general_error_message>, <compiler_message>, <line_number>, <column
_number> ] in case of compile error, numbers are 1-based. | |
333 // or throws exception with message. | |
334 /** | |
335 * @param {number} scriptId | |
336 * @param {string} newSource | |
337 * @param {boolean} preview | |
338 * @return {!Array<*>} | |
339 */ | |
340 DebuggerScript.liveEditScriptSource = function(scriptId, newSource, preview) | |
341 { | |
342 var scripts = Debug.scripts(); | |
343 var scriptToEdit = null; | |
344 for (var i = 0; i < scripts.length; i++) { | |
345 if (scripts[i].id == scriptId) { | |
346 scriptToEdit = scripts[i]; | |
347 break; | |
348 } | |
349 } | |
350 if (!scriptToEdit) | |
351 throw("Script not found"); | |
352 | |
353 var changeLog = []; | |
354 try { | |
355 var result = Debug.LiveEdit.SetScriptSource(scriptToEdit, newSource, pre
view, changeLog); | |
356 return [0, result.stack_modified]; | |
357 } catch (e) { | |
358 if (e instanceof Debug.LiveEdit.Failure && "details" in e) { | |
359 var details = /** @type {!LiveEditErrorDetails} */(e.details); | |
360 if (details.type === "liveedit_compile_error") { | |
361 var startPosition = details.position.start; | |
362 return [1, String(e), String(details.syntaxErrorMessage), Number
(startPosition.line), Number(startPosition.column)]; | |
363 } | |
364 } | |
365 throw e; | |
366 } | |
367 } | |
368 | |
369 /** | |
370 * @param {!ExecutionState} execState | |
371 */ | |
372 DebuggerScript.clearBreakpoints = function(execState) | |
373 { | |
374 Debug.clearAllBreakPoints(); | |
375 } | |
376 | |
377 /** | |
378 * @param {!ExecutionState} execState | |
379 * @param {!{enabled: boolean}} info | |
380 */ | |
381 DebuggerScript.setBreakpointsActivated = function(execState, info) | |
382 { | |
383 Debug.debuggerFlags().breakPointsActive.setValue(info.enabled); | |
384 } | |
385 | |
386 /** | |
387 * @param {!BreakEvent} eventData | |
388 */ | |
389 DebuggerScript.getBreakpointNumbers = function(eventData) | |
390 { | |
391 var breakpoints = eventData.breakPointsHit(); | |
392 var numbers = []; | |
393 if (!breakpoints) | |
394 return numbers; | |
395 | |
396 for (var i = 0; i < breakpoints.length; i++) { | |
397 var breakpoint = breakpoints[i]; | |
398 var scriptBreakPoint = breakpoint.script_break_point(); | |
399 numbers.push(scriptBreakPoint ? scriptBreakPoint.number() : breakpoint.n
umber()); | |
400 } | |
401 return numbers; | |
402 } | |
403 | |
404 // NOTE: This function is performance critical, as it can be run on every | |
405 // statement that generates an async event (like addEventListener) to support | |
406 // asynchronous call stacks. Thus, when possible, initialize the data lazily. | |
407 /** | |
408 * @param {!FrameMirror} frameMirror | |
409 * @return {!JavaScriptCallFrame} | |
410 */ | |
411 DebuggerScript._frameMirrorToJSCallFrame = function(frameMirror) | |
412 { | |
413 // Stuff that can not be initialized lazily (i.e. valid while paused with a
valid break_id). | |
414 // The frameMirror and scopeMirror can be accessed only while paused on the
debugger. | |
415 var frameDetails = frameMirror.details(); | |
416 | |
417 var funcObject = frameDetails.func(); | |
418 var sourcePosition = frameDetails.sourcePosition(); | |
419 var thisObject = frameDetails.receiver(); | |
420 | |
421 var isAtReturn = !!frameDetails.isAtReturn(); | |
422 var returnValue = isAtReturn ? frameDetails.returnValue() : undefined; | |
423 | |
424 var scopeMirrors = frameMirror.allScopes(false); | |
425 /** @type {!Array<ScopeType>} */ | |
426 var scopeTypes = new Array(scopeMirrors.length); | |
427 /** @type {?Array<!Object>} */ | |
428 var scopeObjects = new Array(scopeMirrors.length); | |
429 /** @type {!Array<string|undefined>} */ | |
430 var scopeNames = new Array(scopeMirrors.length); | |
431 /** @type {?Array<number>} */ | |
432 var scopeStartPositions = new Array(scopeMirrors.length); | |
433 /** @type {?Array<number>} */ | |
434 var scopeEndPositions = new Array(scopeMirrors.length); | |
435 /** @type {?Array<function()|null>} */ | |
436 var scopeFunctions = new Array(scopeMirrors.length); | |
437 for (var i = 0; i < scopeMirrors.length; ++i) { | |
438 var scopeDetails = scopeMirrors[i].details(); | |
439 scopeTypes[i] = scopeDetails.type(); | |
440 scopeObjects[i] = scopeDetails.object(); | |
441 scopeNames[i] = scopeDetails.name(); | |
442 scopeStartPositions[i] = scopeDetails.startPosition ? scopeDetails.start
Position() : 0; | |
443 scopeEndPositions[i] = scopeDetails.endPosition ? scopeDetails.endPositi
on() : 0; | |
444 scopeFunctions[i] = scopeDetails.func ? scopeDetails.func() : null; | |
445 } | |
446 | |
447 // Calculated lazily. | |
448 var scopeChain; | |
449 var funcMirror; | |
450 var location; | |
451 /** @type {!Array<?RawLocation>} */ | |
452 var scopeStartLocations; | |
453 /** @type {!Array<?RawLocation>} */ | |
454 var scopeEndLocations; | |
455 var details; | |
456 | |
457 /** | |
458 * @param {!ScriptMirror|undefined} script | |
459 * @param {number} pos | |
460 * @return {?RawLocation} | |
461 */ | |
462 function createLocation(script, pos) | |
463 { | |
464 if (!script) | |
465 return null; | |
466 | |
467 var location = script.locationFromPosition(pos, true); | |
468 return { | |
469 "lineNumber": location.line, | |
470 "columnNumber": location.column, | |
471 "scriptId": String(script.id()) | |
472 } | |
473 } | |
474 | |
475 /** | |
476 * @return {!Array<!Object>} | |
477 */ | |
478 function ensureScopeChain() | |
479 { | |
480 if (!scopeChain) { | |
481 scopeChain = []; | |
482 scopeStartLocations = []; | |
483 scopeEndLocations = []; | |
484 for (var i = 0, j = 0; i < scopeObjects.length; ++i) { | |
485 var scopeObject = DebuggerScript._buildScopeObject(scopeTypes[i]
, scopeObjects[i]); | |
486 if (scopeObject) { | |
487 scopeTypes[j] = scopeTypes[i]; | |
488 scopeNames[j] = scopeNames[i]; | |
489 scopeChain[j] = scopeObject; | |
490 | |
491 var funcMirror = scopeFunctions ? MakeMirror(scopeFunctions[
i]) : null; | |
492 if (!funcMirror || !funcMirror.isFunction()) | |
493 funcMirror = new UnresolvedFunctionMirror(funcObject); | |
494 | |
495 var script = /** @type {!FunctionMirror} */(funcMirror).scri
pt(); | |
496 scopeStartLocations[j] = createLocation(script, scopeStartPo
sitions[i]); | |
497 scopeEndLocations[j] = createLocation(script, scopeEndPositi
ons[i]); | |
498 ++j; | |
499 } | |
500 } | |
501 scopeTypes.length = scopeChain.length; | |
502 scopeNames.length = scopeChain.length; | |
503 scopeObjects = null; // Free for GC. | |
504 scopeFunctions = null; | |
505 scopeStartPositions = null; | |
506 scopeEndPositions = null; | |
507 } | |
508 return scopeChain; | |
509 } | |
510 | |
511 /** | |
512 * @return {!JavaScriptCallFrameDetails} | |
513 */ | |
514 function lazyDetails() | |
515 { | |
516 if (!details) { | |
517 var scopeObjects = ensureScopeChain(); | |
518 var script = ensureFuncMirror().script(); | |
519 /** @type {!Array<Scope>} */ | |
520 var scopes = []; | |
521 for (var i = 0; i < scopeObjects.length; ++i) { | |
522 var scope = { | |
523 "type": /** @type {string} */(DebuggerScript._scopeTypeNames
.get(scopeTypes[i])), | |
524 "object": scopeObjects[i], | |
525 }; | |
526 if (scopeNames[i]) | |
527 scope.name = scopeNames[i]; | |
528 if (scopeStartLocations[i]) | |
529 scope.startLocation = /** @type {!RawLocation} */(scopeStart
Locations[i]); | |
530 if (scopeEndLocations[i]) | |
531 scope.endLocation = /** @type {!RawLocation} */(scopeEndLoca
tions[i]); | |
532 scopes.push(scope); | |
533 } | |
534 details = { | |
535 "functionName": ensureFuncMirror().debugName(), | |
536 "location": { | |
537 "lineNumber": line(), | |
538 "columnNumber": column(), | |
539 "scriptId": String(script.id()) | |
540 }, | |
541 "this": thisObject, | |
542 "scopeChain": scopes | |
543 }; | |
544 var functionLocation = ensureFuncMirror().sourceLocation(); | |
545 if (functionLocation) { | |
546 details.functionLocation = { | |
547 "lineNumber": functionLocation.line, | |
548 "columnNumber": functionLocation.column, | |
549 "scriptId": String(script.id()) | |
550 }; | |
551 } | |
552 if (isAtReturn) | |
553 details.returnValue = returnValue; | |
554 } | |
555 return details; | |
556 } | |
557 | |
558 /** | |
559 * @return {!FunctionMirror} | |
560 */ | |
561 function ensureFuncMirror() | |
562 { | |
563 if (!funcMirror) { | |
564 funcMirror = MakeMirror(funcObject); | |
565 if (!funcMirror.isFunction()) | |
566 funcMirror = new UnresolvedFunctionMirror(funcObject); | |
567 } | |
568 return /** @type {!FunctionMirror} */(funcMirror); | |
569 } | |
570 | |
571 /** | |
572 * @return {!{line: number, column: number}} | |
573 */ | |
574 function ensureLocation() | |
575 { | |
576 if (!location) { | |
577 var script = ensureFuncMirror().script(); | |
578 if (script) | |
579 location = script.locationFromPosition(sourcePosition, true); | |
580 if (!location) | |
581 location = { line: 0, column: 0 }; | |
582 } | |
583 return location; | |
584 } | |
585 | |
586 /** | |
587 * @return {number} | |
588 */ | |
589 function line() | |
590 { | |
591 return ensureLocation().line; | |
592 } | |
593 | |
594 /** | |
595 * @return {number} | |
596 */ | |
597 function column() | |
598 { | |
599 return ensureLocation().column; | |
600 } | |
601 | |
602 /** | |
603 * @return {number} | |
604 */ | |
605 function contextId() | |
606 { | |
607 var mirror = ensureFuncMirror(); | |
608 // Old V8 do not have context() function on these objects | |
609 if (!mirror.context) | |
610 return DebuggerScript._executionContextId(mirror.script().value().co
ntext_data); | |
611 var context = mirror.context(); | |
612 if (context) | |
613 return DebuggerScript._executionContextId(context.data()); | |
614 return 0; | |
615 } | |
616 | |
617 /** | |
618 * @return {number|undefined} | |
619 */ | |
620 function sourceID() | |
621 { | |
622 var script = ensureFuncMirror().script(); | |
623 return script && script.id(); | |
624 } | |
625 | |
626 /** | |
627 * @param {string} expression | |
628 * @return {*} | |
629 */ | |
630 function evaluate(expression) | |
631 { | |
632 return frameMirror.evaluate(expression, false).value(); | |
633 } | |
634 | |
635 /** @return {undefined} */ | |
636 function restart() | |
637 { | |
638 return frameMirror.restart(); | |
639 } | |
640 | |
641 /** | |
642 * @param {number} scopeNumber | |
643 * @param {string} variableName | |
644 * @param {*} newValue | |
645 */ | |
646 function setVariableValue(scopeNumber, variableName, newValue) | |
647 { | |
648 var scopeMirror = frameMirror.scope(scopeNumber); | |
649 if (!scopeMirror) | |
650 throw new Error("Incorrect scope index"); | |
651 scopeMirror.setVariableValue(variableName, newValue); | |
652 } | |
653 | |
654 return { | |
655 "sourceID": sourceID, | |
656 "line": line, | |
657 "column": column, | |
658 "contextId": contextId, | |
659 "thisObject": thisObject, | |
660 "evaluate": evaluate, | |
661 "restart": restart, | |
662 "setVariableValue": setVariableValue, | |
663 "isAtReturn": isAtReturn, | |
664 "details": lazyDetails | |
665 }; | |
666 } | |
667 | |
668 /** | |
669 * @param {number} scopeType | |
670 * @param {!Object} scopeObject | |
671 * @return {!Object|undefined} | |
672 */ | |
673 DebuggerScript._buildScopeObject = function(scopeType, scopeObject) | |
674 { | |
675 var result; | |
676 switch (scopeType) { | |
677 case ScopeType.Local: | |
678 case ScopeType.Closure: | |
679 case ScopeType.Catch: | |
680 case ScopeType.Block: | |
681 case ScopeType.Script: | |
682 // For transient objects we create a "persistent" copy that contains | |
683 // the same properties. | |
684 // Reset scope object prototype to null so that the proto properties | |
685 // don't appear in the local scope section. | |
686 var properties = /** @type {!ObjectMirror} */(MakeMirror(scopeObject, tr
ue /* transient */)).properties(); | |
687 // Almost always Script scope will be empty, so just filter out that noi
se. | |
688 // Also drop empty Block scopes, should we get any. | |
689 if (!properties.length && (scopeType === ScopeType.Script || scopeType =
== ScopeType.Block)) | |
690 break; | |
691 result = { __proto__: null }; | |
692 for (var j = 0; j < properties.length; j++) { | |
693 var name = properties[j].name(); | |
694 if (name.length === 0 || name.charAt(0) === ".") | |
695 continue; // Skip internal variables like ".arguments" and varia
bles with empty name | |
696 result[name] = properties[j].value_; | |
697 } | |
698 break; | |
699 case ScopeType.Global: | |
700 case ScopeType.With: | |
701 result = scopeObject; | |
702 break; | |
703 } | |
704 return result; | |
705 } | |
706 | |
707 // We never resolve Mirror by its handle so to avoid memory leaks caused by Mirr
ors in the cache we disable it. | |
708 ToggleMirrorCache(false); | |
709 | |
710 return DebuggerScript; | |
711 })(); | |
OLD | NEW |