Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(497)

Side by Side Diff: test/debugger/test-api.js

Issue 2497973002: [debug-wrapper] Further extend the debug wrapper (Closed)
Patch Set: One more test Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2016 the V8 project authors. All rights reserved. 1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 "use strict"; 5 "use strict";
6 6
7 // If true, prints all messages sent and received by inspector. 7 // If true, prints all messages sent and received by inspector.
8 const printProtocolMessages = false; 8 const printProtocolMessages = false;
9 9
10 // The active wrapper instance. 10 // The active wrapper instance.
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 return breakid; 148 return breakid;
149 } 149 }
150 150
151 clearBreakPoint(breakid) { 151 clearBreakPoint(breakid) {
152 const {msgid, msg} = this.createMessage( 152 const {msgid, msg} = this.createMessage(
153 "Debugger.removeBreakpoint", { breakpointId : breakid }); 153 "Debugger.removeBreakpoint", { breakpointId : breakid });
154 this.sendMessage(msg); 154 this.sendMessage(msg);
155 this.takeReplyChecked(msgid); 155 this.takeReplyChecked(msgid);
156 } 156 }
157 157
158 // Returns the serialized result of the given expression. For example: 158 debuggerFlags() {
159 // {"type":"number", "value":33, "description":"33"}. 159 return { breakPointsActive :
160 evaluate(frameid, expression) { 160 { setValue : (enabled) => this.setBreakPointsActive(enabled) }
161 };
162 }
163
164 scripts() {
165 // Collect all scripts in the heap.
166 return %DebugGetLoadedScripts();
167 }
168
169 setBreakPointsActive(enabled) {
161 const {msgid, msg} = this.createMessage( 170 const {msgid, msg} = this.createMessage(
162 "Debugger.evaluateOnCallFrame", 171 "Debugger.setBreakpointsActive", { active : enabled });
163 { callFrameId : frameid,
164 expression : expression
165 });
166 this.sendMessage(msg); 172 this.sendMessage(msg);
167 173 this.takeReplyChecked(msgid);
168 const reply = this.takeReplyChecked(msgid);
169 return reply.result.result;
170 } 174 }
171 175
172 // --- Internal methods. ----------------------------------------------------- 176 // --- Internal methods. -----------------------------------------------------
173 177
174 getNextMessageId() { 178 getNextMessageId() {
175 return this.nextMessageId++; 179 return this.nextMessageId++;
176 } 180 }
177 181
178 createMessage(method, params) { 182 createMessage(method, params) {
179 const id = this.getNextMessageId(); 183 const id = this.getNextMessageId();
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
229 case "local": return this.ScopeType.Local; 233 case "local": return this.ScopeType.Local;
230 case "with": return this.ScopeType.With; 234 case "with": return this.ScopeType.With;
231 case "closure": return this.ScopeType.Closure; 235 case "closure": return this.ScopeType.Closure;
232 case "catch": return this.ScopeType.Catch; 236 case "catch": return this.ScopeType.Catch;
233 case "block": return this.ScopeType.Block; 237 case "block": return this.ScopeType.Block;
234 case "script": return this.ScopeType.Script; 238 case "script": return this.ScopeType.Script;
235 default: %AbortJS("Unexpected scope type"); 239 default: %AbortJS("Unexpected scope type");
236 } 240 }
237 } 241 }
238 242
243 execStateScopeObjectProperty(serialized_scope, prop) {
244 let found = null;
245 for (let i = 0; i < serialized_scope.length; i++) {
246 const elem = serialized_scope[i];
247 if (elem.name == prop) {
248 found = elem;
249 break;
250 }
251 }
252
253 if (found == null) return { isUndefined : true }
254
255 const val = { value : () => found.value.value };
256 return { value : () => val,
257 isUndefined : () => found.value.type == "undefined"
258 };
259 }
260
239 // Returns an array of property descriptors of the scope object. 261 // Returns an array of property descriptors of the scope object.
240 // This is in contrast to the original API, which simply passed object 262 // This is in contrast to the original API, which simply passed object
241 // mirrors. 263 // mirrors.
242 execStateScopeObject(obj) { 264 execStateScopeObject(obj) {
243 const serialized_scope = this.getProperties(obj.objectId); 265 const serialized_scope = this.getProperties(obj.objectId);
244 const scope = {} 266 const scope = this.propertiesToObject(serialized_scope);
245 const scope_tuples = serialized_scope.forEach((elem) => { 267 return { value : () => scope,
268 property : (prop) =>
269 this.execStateScopeObjectProperty(serialized_scope, prop)
270 };
271 }
272
273 setVariableValue(frame, scope_index, name, value) {
274 const frameid = frame.callFrameId;
275 const {msgid, msg} = this.createMessage(
276 "Debugger.setVariableValue",
277 { callFrameId : frameid,
278 scopeNumber : scope_index,
279 variableName : name,
280 newValue : { value : value }
281 });
282 this.sendMessage(msg);
283 this.takeReplyChecked(msgid);
284 }
285
286 execStateScope(frame, scope_index) {
287 const scope = frame.scopeChain[scope_index];
288 return { scopeType : () => this.execStateScopeType(scope.type),
289 scopeObject : () => this.execStateScopeObject(scope.object),
290 setVariableValue :
291 (name, value) => this.setVariableValue(frame, scope_index,
292 name, value)
293 };
294 }
295
296 // Takes a list of properties as produced by getProperties and turns them
297 // into an object.
298 propertiesToObject(props) {
299 const obj = {}
300 props.forEach((elem) => {
246 const key = elem.name; 301 const key = elem.name;
247 302
248 let value; 303 let value;
249 if (elem.value) { 304 if (elem.value) {
250 // Some properties (e.g. with getters/setters) don't have a value. 305 // Some properties (e.g. with getters/setters) don't have a value.
251 switch (elem.value.type) { 306 switch (elem.value.type) {
252 case "undefined": value = undefined; break; 307 case "undefined": value = undefined; break;
253 default: value = elem.value.value; break; 308 default: value = elem.value.value; break;
254 } 309 }
255 } 310 }
256 311
257 scope[key] = value; 312 obj[key] = value;
258 }) 313 })
259 314
260 return { value : () => scope }; 315 return obj;
261 }
262
263 execStateScope(scope) {
264 return { scopeType : () => this.execStateScopeType(scope.type),
265 scopeObject : () => this.execStateScopeObject(scope.object)
266 };
267 } 316 }
268 317
269 getProperties(objectId) { 318 getProperties(objectId) {
270 const {msgid, msg} = this.createMessage( 319 const {msgid, msg} = this.createMessage(
271 "Runtime.getProperties", { objectId : objectId }); 320 "Runtime.getProperties", { objectId : objectId });
272 this.sendMessage(msg); 321 this.sendMessage(msg);
273 const reply = this.takeReplyChecked(msgid); 322 const reply = this.takeReplyChecked(msgid);
274 return reply.result.result; 323 return reply.result.result;
275 } 324 }
276 325
(...skipping 28 matching lines...) Expand all
305 354
306 let localValue; 355 let localValue;
307 switch (local.value.type) { 356 switch (local.value.type) {
308 case "undefined": localValue = undefined; break; 357 case "undefined": localValue = undefined; break;
309 default: localValue = local.value.value; break; 358 default: localValue = local.value.value; break;
310 } 359 }
311 360
312 return { value : () => localValue }; 361 return { value : () => localValue };
313 } 362 }
314 363
315 execStateFrameEvaluate(frame, expr) { 364 reconstructRemoteObject(obj) {
365 let value = obj.value;
366 if (obj.type == "object") {
367 if (obj.subtype == "error") {
368 const desc = obj.description;
369 switch (obj.className) {
370 case "EvalError": throw new EvalError(desc);
371 case "RangeError": throw new RangeError(desc);
372 case "ReferenceError": throw new ReferenceError(desc);
373 case "SyntaxError": throw new SyntaxError(desc);
374 case "TypeError": throw new TypeError(desc);
375 case "URIError": throw new URIError(desc);
376 default: throw new Error(desc);
377 }
378 } else if (obj.subtype == "array") {
379 const array = [];
380 const props = this.propertiesToObject(
381 this.getProperties(obj.objectId));
382 for (let i = 0; i < props.length; i++) {
383 array[i] = props[i];
384 }
385 value = array;
386 }
387 }
388
389 return { value : () => value,
390 isUndefined : () => obj.type == "undefined"
391 };
392
393 }
394
395 evaluateOnCallFrame(frame, expr) {
316 const frameid = frame.callFrameId; 396 const frameid = frame.callFrameId;
317 const {msgid, msg} = this.createMessage( 397 const {msgid, msg} = this.createMessage(
318 "Debugger.evaluateOnCallFrame", 398 "Debugger.evaluateOnCallFrame",
319 { callFrameId : frameid, 399 { callFrameId : frameid,
320 expression : expr 400 expression : expr
321 }); 401 });
322 this.sendMessage(msg); 402 this.sendMessage(msg);
323 const reply = this.takeReplyChecked(msgid); 403 const reply = this.takeReplyChecked(msgid);
324 404
325 const result = reply.result.result; 405 const result = reply.result.result;
326 if (result.subtype == "error") { 406 return this.reconstructRemoteObject(result);
327 throw new Error(result.description);
328 }
329
330 return { value : () => result.value };
331 } 407 }
332 408
333 execStateFrame(frame) { 409 execStateFrame(frame) {
334 const scriptid = parseInt(frame.location.scriptId); 410 const scriptid = parseInt(frame.location.scriptId);
335 const line = frame.location.lineNumber; 411 const line = frame.location.lineNumber;
336 const column = frame.location.columnNumber; 412 const column = frame.location.columnNumber;
337 const loc = %ScriptLocationFromLine2(scriptid, line, column, 0); 413 const loc = %ScriptLocationFromLine2(scriptid, line, column, 0);
338 const func = { name : () => frame.functionName }; 414 const func = { name : () => frame.functionName };
339 return { sourceLineText : () => loc.sourceText, 415
340 evaluate : (expr) => this.execStateFrameEvaluate(frame, expr), 416 function allScopes() {
417 const scopes = [];
418 for (let i = 0; i < frame.scopeChain.length; i++) {
419 scopes.push(this.execStateScope(frame, i));
420 }
421 return scopes;
422 };
423
424 return { sourceColumn : () => loc.column,
425 sourceLine : () => loc.line + 1,
426 sourceLineText : () => loc.sourceText,
427 evaluate : (expr) => this.evaluateOnCallFrame(frame, expr),
341 functionName : () => frame.functionName, 428 functionName : () => frame.functionName,
342 func : () => func, 429 func : () => func,
343 localCount : () => this.execStateFrameLocalCount(frame), 430 localCount : () => this.execStateFrameLocalCount(frame),
344 localName : (ix) => this.execStateFrameLocalName(frame, ix), 431 localName : (ix) => this.execStateFrameLocalName(frame, ix),
345 localValue: (ix) => this.execStateFrameLocalValue(frame, ix), 432 localValue: (ix) => this.execStateFrameLocalValue(frame, ix),
346 scopeCount : () => frame.scopeChain.length, 433 scopeCount : () => frame.scopeChain.length,
347 scope : (index) => this.execStateScope(frame.scopeChain[index]), 434 scope : (index) => this.execStateScope(frame, index),
348 allScopes : () => frame.scopeChain.map( 435 allScopes : allScopes.bind(this)
349 this.execStateScope.bind(this))
350 }; 436 };
351 } 437 }
352 438
439 eventDataException(params) {
440 switch (params.data.type) {
441 case "string": {
442 return params.data.value;
443 }
444 case "object": {
445 const props = this.getProperties(params.data.objectId);
446 return this.propertiesToObject(props);
447 }
448 default: {
449 return undefined;
450 }
451 }
452 }
453
454 eventDataScriptSource(id) {
455 const {msgid, msg} = this.createMessage(
456 "Debugger.getScriptSource", { scriptId : id });
457 this.sendMessage(msg);
458 const reply = this.takeReplyChecked(msgid);
459 return reply.result.scriptSource;
460 }
461
462 eventDataScriptSetSource(id, src) {
463 const {msgid, msg} = this.createMessage(
464 "Debugger.setScriptSource", { scriptId : id, scriptSource : src });
465 this.sendMessage(msg);
466 this.takeReplyChecked(msgid);
467 }
468
469 eventDataScript(params) {
470 const id = params.scriptId;
471 const name = params.url ? params.url : undefined;
472
473 return { id : () => id,
474 name : () => name,
475 source : () => this.eventDataScriptSource(id),
476 setSource : (src) => this.eventDataScriptSetSource(id, src)
477 };
478 }
479
353 // --- Message handlers. ----------------------------------------------------- 480 // --- Message handlers. -----------------------------------------------------
354 481
355 dispatchMessage(message) { 482 dispatchMessage(message) {
356 const method = message.method; 483 const method = message.method;
357 if (method == "Debugger.paused") { 484 if (method == "Debugger.paused") {
358 this.handleDebuggerPaused(message); 485 this.handleDebuggerPaused(message);
359 } else if (method == "Debugger.scriptParsed") { 486 } else if (method == "Debugger.scriptParsed") {
360 this.handleDebuggerScriptParsed(message); 487 this.handleDebuggerScriptParsed(message);
488 } else if (method == "Debugger.scriptFailedToParse") {
489 this.handleDebuggerScriptFailedToParse(message);
361 } 490 }
362 } 491 }
363 492
364 handleDebuggerPaused(message) { 493 handleDebuggerPaused(message) {
365 const params = message.params; 494 const params = message.params;
366 495
367 var debugEvent; 496 var debugEvent;
368 switch (params.reason) { 497 switch (params.reason) {
369 case "exception": 498 case "exception":
370 case "promiseRejection": 499 case "promiseRejection":
(...skipping 13 matching lines...) Expand all
384 prepareStep : this.execStatePrepareStep.bind(this), 513 prepareStep : this.execStatePrepareStep.bind(this),
385 frame : (index) => this.execStateFrame( 514 frame : (index) => this.execStateFrame(
386 index ? params.callFrames[index] 515 index ? params.callFrames[index]
387 : params.callFrames[0]), 516 : params.callFrames[0]),
388 frameCount : () => params.callFrames.length 517 frameCount : () => params.callFrames.length
389 }; 518 };
390 519
391 let eventData = this.execStateFrame(params.callFrames[0]); 520 let eventData = this.execStateFrame(params.callFrames[0]);
392 if (debugEvent == this.DebugEvent.Exception) { 521 if (debugEvent == this.DebugEvent.Exception) {
393 eventData.uncaught = () => params.data.uncaught; 522 eventData.uncaught = () => params.data.uncaught;
523 eventData.exception = () => this.eventDataException(params);
394 } 524 }
395 525
396 this.invokeListener(debugEvent, execState, eventData); 526 this.invokeListener(debugEvent, execState, eventData);
397 } 527 }
398 528
399 handleDebuggerScriptParsed(message) { 529 handleDebuggerScriptParsed(message) {
400 const params = message.params; 530 const params = message.params;
401 let eventData = { scriptId : params.scriptId, 531 let eventData = { scriptId : params.scriptId,
532 script : () => this.eventDataScript(params),
402 eventType : this.DebugEvent.AfterCompile 533 eventType : this.DebugEvent.AfterCompile
403 } 534 }
404 535
405 // TODO(jgruber): Arguments as needed. Still completely missing exec_state, 536 // TODO(jgruber): Arguments as needed. Still completely missing exec_state,
406 // and eventData used to contain the script mirror instead of its id. 537 // and eventData used to contain the script mirror instead of its id.
407 this.invokeListener(this.DebugEvent.AfterCompile, undefined, eventData, 538 this.invokeListener(this.DebugEvent.AfterCompile, undefined, eventData,
408 undefined); 539 undefined);
409 } 540 }
410 541
542 handleDebuggerScriptFailedToParse(message) {
543 const params = message.params;
544 let eventData = { scriptId : params.scriptId,
545 script : () => this.eventDataScript(params),
546 eventType : this.DebugEvent.CompileError
547 }
548
549 // TODO(jgruber): Arguments as needed. Still completely missing exec_state,
550 // and eventData used to contain the script mirror instead of its id.
551 this.invokeListener(this.DebugEvent.CompileError, undefined, eventData,
552 undefined);
553 }
554
411 invokeListener(event, exec_state, event_data, data) { 555 invokeListener(event, exec_state, event_data, data) {
412 if (this.listener) { 556 if (this.listener) {
413 this.listener(event, exec_state, event_data, data); 557 this.listener(event, exec_state, event_data, data);
414 } 558 }
415 } 559 }
416 } 560 }
417 561
418 // Simulate the debug object generated by --expose-debug-as debug. 562 // Simulate the debug object generated by --expose-debug-as debug.
419 var debug = { instance : undefined }; 563 var debug = { instance : undefined };
420 564
421 Object.defineProperty(debug, 'Debug', { get: function() { 565 Object.defineProperty(debug, 'Debug', { get: function() {
422 if (!debug.instance) { 566 if (!debug.instance) {
423 debug.instance = new DebugWrapper(); 567 debug.instance = new DebugWrapper();
424 debug.instance.enable(); 568 debug.instance.enable();
425 } 569 }
426 return debug.instance; 570 return debug.instance;
427 }}); 571 }});
428 572
429 Object.defineProperty(debug, 'ScopeType', { get: function() { 573 Object.defineProperty(debug, 'ScopeType', { get: function() {
430 const instance = debug.Debug; 574 const instance = debug.Debug;
431 return instance.ScopeType; 575 return instance.ScopeType;
432 }}); 576 }});
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698