blob: 6993274f09efe2bf1bfcbb76b393f9bc0025e80b [file] [log] [blame]
Ben Murdoch014dc512016-03-22 12:00:34 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5(function (global, utils) {
6"use strict";
7
8// ----------------------------------------------------------------------------
9// Imports
10
11var FrameMirror = global.FrameMirror;
12var GlobalArray = global.Array;
13var GlobalRegExp = global.RegExp;
14var IsNaN = global.isNaN;
Ben Murdoch014dc512016-03-22 12:00:34 +000015var MakeMirror = global.MakeMirror;
Ben Murdoch014dc512016-03-22 12:00:34 +000016var MathMin = global.Math.min;
17var Mirror = global.Mirror;
Ben Murdoch014dc512016-03-22 12:00:34 +000018var ValueMirror = global.ValueMirror;
19
Ben Murdoch014dc512016-03-22 12:00:34 +000020//----------------------------------------------------------------------------
21
22// Default number of frames to include in the response to backtrace request.
23var kDefaultBacktraceLength = 10;
24
25var Debug = {};
26
27// Regular expression to skip "crud" at the beginning of a source line which is
28// not really code. Currently the regular expression matches whitespace and
29// comments.
30var sourceLineBeginningSkip = /^(?:\s*(?:\/\*.*?\*\/)*)*/;
31
32// Debug events which can occour in the V8 JavaScript engine. These originate
33// from the API include file debug.h.
34Debug.DebugEvent = { Break: 1,
35 Exception: 2,
Ben Murdoch62ed6312017-06-06 11:06:27 +010036 AfterCompile: 3,
37 CompileError: 4,
38 AsyncTaskEvent: 5 };
Ben Murdoch014dc512016-03-22 12:00:34 +000039
40// Types of exceptions that can be broken upon.
41Debug.ExceptionBreak = { Caught : 0,
42 Uncaught: 1 };
43
44// The different types of steps.
45Debug.StepAction = { StepOut: 0,
46 StepNext: 1,
Ben Murdoch62ed6312017-06-06 11:06:27 +010047 StepIn: 2 };
Ben Murdoch014dc512016-03-22 12:00:34 +000048
49// The different types of scripts matching enum ScriptType in objects.h.
50Debug.ScriptType = { Native: 0,
51 Extension: 1,
Ben Murdochf91f0612016-11-29 16:50:11 +000052 Normal: 2,
53 Wasm: 3};
Ben Murdoch014dc512016-03-22 12:00:34 +000054
55// The different types of script compilations matching enum
56// Script::CompilationType in objects.h.
57Debug.ScriptCompilationType = { Host: 0,
58 Eval: 1,
59 JSON: 2 };
60
61// The different script break point types.
62Debug.ScriptBreakPointType = { ScriptId: 0,
63 ScriptName: 1,
64 ScriptRegExp: 2 };
65
66// The different types of breakpoint position alignments.
67// Must match BreakPositionAlignment in debug.h.
68Debug.BreakPositionAlignment = {
69 Statement: 0,
70 BreakPosition: 1
71};
72
73function ScriptTypeFlag(type) {
74 return (1 << type);
75}
76
77// Globals.
78var next_response_seq = 0;
79var next_break_point_number = 1;
80var break_points = [];
81var script_break_points = [];
82var debugger_flags = {
83 breakPointsActive: {
84 value: true,
85 getValue: function() { return this.value; },
86 setValue: function(value) {
87 this.value = !!value;
88 %SetBreakPointsActive(this.value);
89 }
90 },
91 breakOnCaughtException: {
92 getValue: function() { return Debug.isBreakOnException(); },
93 setValue: function(value) {
94 if (value) {
95 Debug.setBreakOnException();
96 } else {
97 Debug.clearBreakOnException();
98 }
99 }
100 },
101 breakOnUncaughtException: {
102 getValue: function() { return Debug.isBreakOnUncaughtException(); },
103 setValue: function(value) {
104 if (value) {
105 Debug.setBreakOnUncaughtException();
106 } else {
107 Debug.clearBreakOnUncaughtException();
108 }
109 }
110 },
111};
112
113
114// Create a new break point object and add it to the list of break points.
115function MakeBreakPoint(source_position, opt_script_break_point) {
116 var break_point = new BreakPoint(source_position, opt_script_break_point);
117 break_points.push(break_point);
118 return break_point;
119}
120
121
122// Object representing a break point.
123// NOTE: This object does not have a reference to the function having break
124// point as this would cause function not to be garbage collected when it is
125// not used any more. We do not want break points to keep functions alive.
126function BreakPoint(source_position, opt_script_break_point) {
127 this.source_position_ = source_position;
128 if (opt_script_break_point) {
129 this.script_break_point_ = opt_script_break_point;
130 } else {
131 this.number_ = next_break_point_number++;
132 }
Ben Murdoch014dc512016-03-22 12:00:34 +0000133 this.active_ = true;
134 this.condition_ = null;
Ben Murdoch014dc512016-03-22 12:00:34 +0000135}
136
137
138BreakPoint.prototype.number = function() {
139 return this.number_;
140};
141
142
143BreakPoint.prototype.func = function() {
144 return this.func_;
145};
146
147
148BreakPoint.prototype.source_position = function() {
149 return this.source_position_;
150};
151
152
Ben Murdoch014dc512016-03-22 12:00:34 +0000153BreakPoint.prototype.active = function() {
154 if (this.script_break_point()) {
155 return this.script_break_point().active();
156 }
157 return this.active_;
158};
159
160
161BreakPoint.prototype.condition = function() {
162 if (this.script_break_point() && this.script_break_point().condition()) {
163 return this.script_break_point().condition();
164 }
165 return this.condition_;
166};
167
168
Ben Murdoch014dc512016-03-22 12:00:34 +0000169BreakPoint.prototype.script_break_point = function() {
170 return this.script_break_point_;
171};
172
173
174BreakPoint.prototype.enable = function() {
175 this.active_ = true;
176};
177
178
179BreakPoint.prototype.disable = function() {
180 this.active_ = false;
181};
182
183
184BreakPoint.prototype.setCondition = function(condition) {
185 this.condition_ = condition;
186};
187
188
Ben Murdoch014dc512016-03-22 12:00:34 +0000189BreakPoint.prototype.isTriggered = function(exec_state) {
190 // Break point not active - not triggered.
191 if (!this.active()) return false;
192
193 // Check for conditional break point.
194 if (this.condition()) {
195 // If break point has condition try to evaluate it in the top frame.
196 try {
197 var mirror = exec_state.frame(0).evaluate(this.condition());
198 // If no sensible mirror or non true value break point not triggered.
199 if (!(mirror instanceof ValueMirror) || !mirror.value_) {
200 return false;
201 }
202 } catch (e) {
203 // Exception evaluating condition counts as not triggered.
204 return false;
205 }
206 }
207
Ben Murdoch014dc512016-03-22 12:00:34 +0000208 // Break point triggered.
209 return true;
210};
211
212
213// Function called from the runtime when a break point is hit. Returns true if
214// the break point is triggered and supposed to break execution.
215function IsBreakPointTriggered(break_id, break_point) {
216 return break_point.isTriggered(MakeExecutionState(break_id));
217}
218
219
220// Object representing a script break point. The script is referenced by its
221// script name or script id and the break point is represented as line and
222// column.
223function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
224 opt_groupId, opt_position_alignment) {
225 this.type_ = type;
226 if (type == Debug.ScriptBreakPointType.ScriptId) {
227 this.script_id_ = script_id_or_name;
228 } else if (type == Debug.ScriptBreakPointType.ScriptName) {
229 this.script_name_ = script_id_or_name;
230 } else if (type == Debug.ScriptBreakPointType.ScriptRegExp) {
231 this.script_regexp_object_ = new GlobalRegExp(script_id_or_name);
232 } else {
Ben Murdochf91f0612016-11-29 16:50:11 +0000233 throw %make_error(kDebugger, "Unexpected breakpoint type " + type);
Ben Murdoch014dc512016-03-22 12:00:34 +0000234 }
235 this.line_ = opt_line || 0;
236 this.column_ = opt_column;
237 this.groupId_ = opt_groupId;
238 this.position_alignment_ = IS_UNDEFINED(opt_position_alignment)
239 ? Debug.BreakPositionAlignment.Statement : opt_position_alignment;
Ben Murdoch014dc512016-03-22 12:00:34 +0000240 this.active_ = true;
241 this.condition_ = null;
Ben Murdoch014dc512016-03-22 12:00:34 +0000242 this.break_points_ = [];
243}
244
245
Ben Murdoch014dc512016-03-22 12:00:34 +0000246ScriptBreakPoint.prototype.number = function() {
247 return this.number_;
248};
249
250
251ScriptBreakPoint.prototype.groupId = function() {
252 return this.groupId_;
253};
254
255
256ScriptBreakPoint.prototype.type = function() {
257 return this.type_;
258};
259
260
261ScriptBreakPoint.prototype.script_id = function() {
262 return this.script_id_;
263};
264
265
266ScriptBreakPoint.prototype.script_name = function() {
267 return this.script_name_;
268};
269
270
271ScriptBreakPoint.prototype.script_regexp_object = function() {
272 return this.script_regexp_object_;
273};
274
275
276ScriptBreakPoint.prototype.line = function() {
277 return this.line_;
278};
279
280
281ScriptBreakPoint.prototype.column = function() {
282 return this.column_;
283};
284
285
286ScriptBreakPoint.prototype.actual_locations = function() {
287 var locations = [];
288 for (var i = 0; i < this.break_points_.length; i++) {
289 locations.push(this.break_points_[i].actual_location);
290 }
291 return locations;
292};
293
294
295ScriptBreakPoint.prototype.update_positions = function(line, column) {
296 this.line_ = line;
297 this.column_ = column;
298};
299
300
Ben Murdoch014dc512016-03-22 12:00:34 +0000301ScriptBreakPoint.prototype.active = function() {
302 return this.active_;
303};
304
305
306ScriptBreakPoint.prototype.condition = function() {
307 return this.condition_;
308};
309
310
Ben Murdoch014dc512016-03-22 12:00:34 +0000311ScriptBreakPoint.prototype.enable = function() {
312 this.active_ = true;
313};
314
315
316ScriptBreakPoint.prototype.disable = function() {
317 this.active_ = false;
318};
319
320
321ScriptBreakPoint.prototype.setCondition = function(condition) {
322 this.condition_ = condition;
323};
324
325
Ben Murdoch014dc512016-03-22 12:00:34 +0000326// Check whether a script matches this script break point. Currently this is
327// only based on script name.
328ScriptBreakPoint.prototype.matchesScript = function(script) {
329 if (this.type_ == Debug.ScriptBreakPointType.ScriptId) {
330 return this.script_id_ == script.id;
331 } else {
332 // We might want to account columns here as well.
333 if (!(script.line_offset <= this.line_ &&
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100334 this.line_ < script.line_offset + %ScriptLineCount(script))) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000335 return false;
336 }
337 if (this.type_ == Debug.ScriptBreakPointType.ScriptName) {
338 return this.script_name_ == script.nameOrSourceURL();
339 } else if (this.type_ == Debug.ScriptBreakPointType.ScriptRegExp) {
340 return this.script_regexp_object_.test(script.nameOrSourceURL());
341 } else {
Ben Murdochf91f0612016-11-29 16:50:11 +0000342 throw %make_error(kDebugger, "Unexpected breakpoint type " + this.type_);
Ben Murdoch014dc512016-03-22 12:00:34 +0000343 }
344 }
345};
346
347
348// Set the script break point in a script.
349ScriptBreakPoint.prototype.set = function (script) {
350 var column = this.column();
351 var line = this.line();
352 // If the column is undefined the break is on the line. To help locate the
353 // first piece of breakable code on the line try to find the column on the
354 // line which contains some source.
355 if (IS_UNDEFINED(column)) {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100356 var source_line = %ScriptSourceLine(script, line || script.line_offset);
Ben Murdoch014dc512016-03-22 12:00:34 +0000357
358 // Allocate array for caching the columns where the actual source starts.
359 if (!script.sourceColumnStart_) {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100360 script.sourceColumnStart_ = new GlobalArray(%ScriptLineCount(script));
Ben Murdoch014dc512016-03-22 12:00:34 +0000361 }
362
363 // Fill cache if needed and get column where the actual source starts.
364 if (IS_UNDEFINED(script.sourceColumnStart_[line])) {
365 script.sourceColumnStart_[line] =
366 source_line.match(sourceLineBeginningSkip)[0].length;
367 }
368 column = script.sourceColumnStart_[line];
369 }
370
371 // Convert the line and column into an absolute position within the script.
372 var position = Debug.findScriptSourcePosition(script, this.line(), column);
373
374 // If the position is not found in the script (the script might be shorter
375 // than it used to be) just ignore it.
376 if (IS_NULL(position)) return;
377
378 // Create a break point object and set the break point.
379 var break_point = MakeBreakPoint(position, this);
Ben Murdoch014dc512016-03-22 12:00:34 +0000380 var actual_position = %SetScriptBreakPoint(script, position,
381 this.position_alignment_,
382 break_point);
383 if (IS_UNDEFINED(actual_position)) {
384 actual_position = position;
385 }
386 var actual_location = script.locationFromPosition(actual_position, true);
387 break_point.actual_location = { line: actual_location.line,
388 column: actual_location.column,
389 script_id: script.id };
390 this.break_points_.push(break_point);
391 return break_point;
392};
393
394
395// Clear all the break points created from this script break point
396ScriptBreakPoint.prototype.clear = function () {
397 var remaining_break_points = [];
398 for (var i = 0; i < break_points.length; i++) {
399 if (break_points[i].script_break_point() &&
400 break_points[i].script_break_point() === this) {
401 %ClearBreakPoint(break_points[i]);
402 } else {
403 remaining_break_points.push(break_points[i]);
404 }
405 }
406 break_points = remaining_break_points;
407 this.break_points_ = [];
408};
409
410
Ben Murdoch014dc512016-03-22 12:00:34 +0000411Debug.setListener = function(listener, opt_data) {
412 if (!IS_FUNCTION(listener) && !IS_UNDEFINED(listener) && !IS_NULL(listener)) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000413 throw %make_type_error(kDebuggerType);
Ben Murdoch014dc512016-03-22 12:00:34 +0000414 }
415 %SetDebugEventListener(listener, opt_data);
416};
417
418
Ben Murdoch014dc512016-03-22 12:00:34 +0000419// Returns a Script object. If the parameter is a function the return value
420// is the script in which the function is defined. If the parameter is a string
421// the return value is the script for which the script name has that string
422// value. If it is a regexp and there is a unique script whose name matches
423// we return that, otherwise undefined.
424Debug.findScript = function(func_or_script_name) {
425 if (IS_FUNCTION(func_or_script_name)) {
426 return %FunctionGetScript(func_or_script_name);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100427 } else if (%IsRegExp(func_or_script_name)) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000428 var scripts = this.scripts();
Ben Murdoch014dc512016-03-22 12:00:34 +0000429 var last_result = null;
430 var result_count = 0;
431 for (var i in scripts) {
432 var script = scripts[i];
433 if (func_or_script_name.test(script.name)) {
434 last_result = script;
435 result_count++;
436 }
437 }
438 // Return the unique script matching the regexp. If there are more
439 // than one we don't return a value since there is no good way to
440 // decide which one to return. Returning a "random" one, say the
441 // first, would introduce nondeterminism (or something close to it)
442 // because the order is the heap iteration order.
443 if (result_count == 1) {
444 return last_result;
445 } else {
446 return UNDEFINED;
447 }
448 } else {
449 return %GetScript(func_or_script_name);
450 }
451};
452
453// Returns the script source. If the parameter is a function the return value
454// is the script source for the script in which the function is defined. If the
455// parameter is a string the return value is the script for which the script
456// name has that string value.
457Debug.scriptSource = function(func_or_script_name) {
458 return this.findScript(func_or_script_name).source;
459};
460
461
462Debug.source = function(f) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000463 if (!IS_FUNCTION(f)) throw %make_type_error(kDebuggerType);
Ben Murdoch014dc512016-03-22 12:00:34 +0000464 return %FunctionGetSourceCode(f);
465};
466
467
468Debug.sourcePosition = function(f) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000469 if (!IS_FUNCTION(f)) throw %make_type_error(kDebuggerType);
Ben Murdoch014dc512016-03-22 12:00:34 +0000470 return %FunctionGetScriptSourcePosition(f);
471};
472
473
474Debug.findFunctionSourceLocation = function(func, opt_line, opt_column) {
475 var script = %FunctionGetScript(func);
476 var script_offset = %FunctionGetScriptSourcePosition(func);
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100477 return %ScriptLocationFromLine(script, opt_line, opt_column, script_offset);
Ben Murdoch014dc512016-03-22 12:00:34 +0000478};
479
480
481// Returns the character position in a script based on a line number and an
482// optional position within that line.
483Debug.findScriptSourcePosition = function(script, opt_line, opt_column) {
Ben Murdoch13e2dad2016-09-16 13:49:30 +0100484 var location = %ScriptLocationFromLine(script, opt_line, opt_column, 0);
Ben Murdoch014dc512016-03-22 12:00:34 +0000485 return location ? location.position : null;
486};
487
488
489Debug.findBreakPoint = function(break_point_number, remove) {
490 var break_point;
491 for (var i = 0; i < break_points.length; i++) {
492 if (break_points[i].number() == break_point_number) {
493 break_point = break_points[i];
494 // Remove the break point from the list if requested.
495 if (remove) {
496 break_points.splice(i, 1);
497 }
498 break;
499 }
500 }
501 if (break_point) {
502 return break_point;
503 } else {
504 return this.findScriptBreakPoint(break_point_number, remove);
505 }
506};
507
508Debug.findBreakPointActualLocations = function(break_point_number) {
509 for (var i = 0; i < script_break_points.length; i++) {
510 if (script_break_points[i].number() == break_point_number) {
511 return script_break_points[i].actual_locations();
512 }
513 }
514 for (var i = 0; i < break_points.length; i++) {
515 if (break_points[i].number() == break_point_number) {
516 return [break_points[i].actual_location];
517 }
518 }
519 return [];
520};
521
522Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000523 if (!IS_FUNCTION(func)) throw %make_type_error(kDebuggerType);
Ben Murdoch014dc512016-03-22 12:00:34 +0000524 // Break points in API functions are not supported.
525 if (%FunctionIsAPIFunction(func)) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000526 throw %make_error(kDebugger, 'Cannot set break point in native code.');
Ben Murdoch014dc512016-03-22 12:00:34 +0000527 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000528 // Find source position.
529 var source_position =
Ben Murdoch014dc512016-03-22 12:00:34 +0000530 this.findFunctionSourceLocation(func, opt_line, opt_column).position;
Ben Murdoch014dc512016-03-22 12:00:34 +0000531 // Find the script for the function.
532 var script = %FunctionGetScript(func);
533 // Break in builtin JavaScript code is not supported.
534 if (script.type == Debug.ScriptType.Native) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000535 throw %make_error(kDebugger, 'Cannot set break point in native code.');
Ben Murdoch014dc512016-03-22 12:00:34 +0000536 }
537 // If the script for the function has a name convert this to a script break
538 // point.
539 if (script && script.id) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000540 // Find line and column for the position in the script and set a script
541 // break point from that.
542 var location = script.locationFromPosition(source_position, false);
543 return this.setScriptBreakPointById(script.id,
544 location.line, location.column,
545 opt_condition);
546 } else {
547 // Set a break point directly on the function.
548 var break_point = MakeBreakPoint(source_position);
549 var actual_position =
550 %SetFunctionBreakPoint(func, source_position, break_point);
Ben Murdoch014dc512016-03-22 12:00:34 +0000551 var actual_location = script.locationFromPosition(actual_position, true);
552 break_point.actual_location = { line: actual_location.line,
553 column: actual_location.column,
554 script_id: script.id };
555 break_point.setCondition(opt_condition);
556 return break_point.number();
557 }
558};
559
560
561Debug.setBreakPointByScriptIdAndPosition = function(script_id, position,
562 condition, enabled,
563 opt_position_alignment)
564{
565 var break_point = MakeBreakPoint(position);
566 break_point.setCondition(condition);
567 if (!enabled) {
568 break_point.disable();
569 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000570 var script = scriptById(script_id);
571 if (script) {
572 var position_alignment = IS_UNDEFINED(opt_position_alignment)
573 ? Debug.BreakPositionAlignment.Statement : opt_position_alignment;
574 break_point.actual_position = %SetScriptBreakPoint(script, position,
575 position_alignment, break_point);
Ben Murdoch014dc512016-03-22 12:00:34 +0000576 }
577 return break_point;
578};
579
580
581Debug.enableBreakPoint = function(break_point_number) {
582 var break_point = this.findBreakPoint(break_point_number, false);
583 // Only enable if the breakpoint hasn't been deleted:
584 if (break_point) {
585 break_point.enable();
586 }
587};
588
589
590Debug.disableBreakPoint = function(break_point_number) {
591 var break_point = this.findBreakPoint(break_point_number, false);
592 // Only enable if the breakpoint hasn't been deleted:
593 if (break_point) {
594 break_point.disable();
595 }
596};
597
598
599Debug.changeBreakPointCondition = function(break_point_number, condition) {
600 var break_point = this.findBreakPoint(break_point_number, false);
601 break_point.setCondition(condition);
602};
603
604
Ben Murdoch014dc512016-03-22 12:00:34 +0000605Debug.clearBreakPoint = function(break_point_number) {
606 var break_point = this.findBreakPoint(break_point_number, true);
607 if (break_point) {
608 return %ClearBreakPoint(break_point);
609 } else {
610 break_point = this.findScriptBreakPoint(break_point_number, true);
Ben Murdochf91f0612016-11-29 16:50:11 +0000611 if (!break_point) throw %make_error(kDebugger, 'Invalid breakpoint');
Ben Murdoch014dc512016-03-22 12:00:34 +0000612 }
613};
614
615
616Debug.clearAllBreakPoints = function() {
617 for (var i = 0; i < break_points.length; i++) {
618 var break_point = break_points[i];
619 %ClearBreakPoint(break_point);
620 }
621 break_points = [];
622};
623
624
625Debug.disableAllBreakPoints = function() {
626 // Disable all user defined breakpoints:
627 for (var i = 1; i < next_break_point_number; i++) {
628 Debug.disableBreakPoint(i);
629 }
630 // Disable all exception breakpoints:
631 %ChangeBreakOnException(Debug.ExceptionBreak.Caught, false);
632 %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
633};
634
635
636Debug.findScriptBreakPoint = function(break_point_number, remove) {
637 var script_break_point;
638 for (var i = 0; i < script_break_points.length; i++) {
639 if (script_break_points[i].number() == break_point_number) {
640 script_break_point = script_break_points[i];
641 // Remove the break point from the list if requested.
642 if (remove) {
643 script_break_point.clear();
644 script_break_points.splice(i,1);
645 }
646 break;
647 }
648 }
649 return script_break_point;
650};
651
652
653// Sets a breakpoint in a script identified through id or name at the
654// specified source line and column within that line.
655Debug.setScriptBreakPoint = function(type, script_id_or_name,
656 opt_line, opt_column, opt_condition,
657 opt_groupId, opt_position_alignment) {
658 // Create script break point object.
659 var script_break_point =
660 new ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
661 opt_groupId, opt_position_alignment);
662
663 // Assign number to the new script break point and add it.
664 script_break_point.number_ = next_break_point_number++;
665 script_break_point.setCondition(opt_condition);
666 script_break_points.push(script_break_point);
667
668 // Run through all scripts to see if this script break point matches any
669 // loaded scripts.
670 var scripts = this.scripts();
671 for (var i = 0; i < scripts.length; i++) {
672 if (script_break_point.matchesScript(scripts[i])) {
673 script_break_point.set(scripts[i]);
674 }
675 }
676
677 return script_break_point.number();
678};
679
680
681Debug.setScriptBreakPointById = function(script_id,
682 opt_line, opt_column,
683 opt_condition, opt_groupId,
684 opt_position_alignment) {
685 return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
686 script_id, opt_line, opt_column,
687 opt_condition, opt_groupId,
688 opt_position_alignment);
689};
690
691
692Debug.setScriptBreakPointByName = function(script_name,
693 opt_line, opt_column,
694 opt_condition, opt_groupId) {
695 return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptName,
696 script_name, opt_line, opt_column,
697 opt_condition, opt_groupId);
698};
699
700
701Debug.setScriptBreakPointByRegExp = function(script_regexp,
702 opt_line, opt_column,
703 opt_condition, opt_groupId) {
704 return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptRegExp,
705 script_regexp, opt_line, opt_column,
706 opt_condition, opt_groupId);
707};
708
709
710Debug.enableScriptBreakPoint = function(break_point_number) {
711 var script_break_point = this.findScriptBreakPoint(break_point_number, false);
712 script_break_point.enable();
713};
714
715
716Debug.disableScriptBreakPoint = function(break_point_number) {
717 var script_break_point = this.findScriptBreakPoint(break_point_number, false);
718 script_break_point.disable();
719};
720
721
722Debug.changeScriptBreakPointCondition = function(
723 break_point_number, condition) {
724 var script_break_point = this.findScriptBreakPoint(break_point_number, false);
725 script_break_point.setCondition(condition);
726};
727
728
Ben Murdoch014dc512016-03-22 12:00:34 +0000729Debug.scriptBreakPoints = function() {
730 return script_break_points;
731};
732
733
734Debug.clearStepping = function() {
735 %ClearStepping();
736};
737
738Debug.setBreakOnException = function() {
739 return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, true);
740};
741
742Debug.clearBreakOnException = function() {
743 return %ChangeBreakOnException(Debug.ExceptionBreak.Caught, false);
744};
745
746Debug.isBreakOnException = function() {
747 return !!%IsBreakOnException(Debug.ExceptionBreak.Caught);
748};
749
750Debug.setBreakOnUncaughtException = function() {
751 return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, true);
752};
753
754Debug.clearBreakOnUncaughtException = function() {
755 return %ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
756};
757
758Debug.isBreakOnUncaughtException = function() {
759 return !!%IsBreakOnException(Debug.ExceptionBreak.Uncaught);
760};
761
762Debug.showBreakPoints = function(f, full, opt_position_alignment) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000763 if (!IS_FUNCTION(f)) throw %make_error(kDebuggerType);
Ben Murdoch014dc512016-03-22 12:00:34 +0000764 var source = full ? this.scriptSource(f) : this.source(f);
Ben Murdochf91f0612016-11-29 16:50:11 +0000765 var offset = full ? 0 : this.sourcePosition(f);
766 var position_alignment = IS_UNDEFINED(opt_position_alignment)
767 ? Debug.BreakPositionAlignment.Statement : opt_position_alignment;
768 var locations = %GetBreakLocations(f, position_alignment);
Ben Murdoch014dc512016-03-22 12:00:34 +0000769 if (!locations) return source;
770 locations.sort(function(x, y) { return x - y; });
771 var result = "";
772 var prev_pos = 0;
773 var pos;
774 for (var i = 0; i < locations.length; i++) {
775 pos = locations[i] - offset;
776 result += source.slice(prev_pos, pos);
777 result += "[B" + i + "]";
778 prev_pos = pos;
779 }
780 pos = source.length;
781 result += source.substring(prev_pos, pos);
782 return result;
783};
784
785
786// Get all the scripts currently loaded. Locating all the scripts is based on
787// scanning the heap.
788Debug.scripts = function() {
789 // Collect all scripts in the heap.
790 return %DebugGetLoadedScripts();
791};
792
793
Ben Murdochf91f0612016-11-29 16:50:11 +0000794// Get a specific script currently loaded. This is based on scanning the heap.
795// TODO(clemensh): Create a runtime function for this.
796function scriptById(scriptId) {
797 var scripts = Debug.scripts();
798 for (var script of scripts) {
799 if (script.id == scriptId) return script;
800 }
801 return UNDEFINED;
802};
803
804
Ben Murdoch014dc512016-03-22 12:00:34 +0000805Debug.debuggerFlags = function() {
806 return debugger_flags;
807};
808
809Debug.MakeMirror = MakeMirror;
810
811function MakeExecutionState(break_id) {
812 return new ExecutionState(break_id);
813}
814
815function ExecutionState(break_id) {
816 this.break_id = break_id;
817 this.selected_frame = 0;
818}
819
820ExecutionState.prototype.prepareStep = function(action) {
821 if (action === Debug.StepAction.StepIn ||
822 action === Debug.StepAction.StepOut ||
Ben Murdoch62ed6312017-06-06 11:06:27 +0100823 action === Debug.StepAction.StepNext) {
Ben Murdoch014dc512016-03-22 12:00:34 +0000824 return %PrepareStep(this.break_id, action);
825 }
Ben Murdochf91f0612016-11-29 16:50:11 +0000826 throw %make_type_error(kDebuggerType);
Ben Murdoch014dc512016-03-22 12:00:34 +0000827};
828
Ben Murdoch62ed6312017-06-06 11:06:27 +0100829ExecutionState.prototype.evaluateGlobal = function(source) {
830 return MakeMirror(%DebugEvaluateGlobal(this.break_id, source));
Ben Murdoch014dc512016-03-22 12:00:34 +0000831};
832
833ExecutionState.prototype.frameCount = function() {
834 return %GetFrameCount(this.break_id);
835};
836
Ben Murdoch014dc512016-03-22 12:00:34 +0000837ExecutionState.prototype.frame = function(opt_index) {
838 // If no index supplied return the selected frame.
839 if (opt_index == null) opt_index = this.selected_frame;
840 if (opt_index < 0 || opt_index >= this.frameCount()) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000841 throw %make_type_error(kDebuggerFrame);
Ben Murdoch014dc512016-03-22 12:00:34 +0000842 }
843 return new FrameMirror(this.break_id, opt_index);
844};
845
846ExecutionState.prototype.setSelectedFrame = function(index) {
847 var i = TO_NUMBER(index);
848 if (i < 0 || i >= this.frameCount()) {
Ben Murdochf91f0612016-11-29 16:50:11 +0000849 throw %make_type_error(kDebuggerFrame);
Ben Murdoch014dc512016-03-22 12:00:34 +0000850 }
851 this.selected_frame = i;
852};
853
854ExecutionState.prototype.selectedFrame = function() {
855 return this.selected_frame;
856};
857
Ben Murdoch014dc512016-03-22 12:00:34 +0000858function MakeBreakEvent(break_id, break_points_hit) {
859 return new BreakEvent(break_id, break_points_hit);
860}
861
862
863function BreakEvent(break_id, break_points_hit) {
864 this.frame_ = new FrameMirror(break_id, 0);
865 this.break_points_hit_ = break_points_hit;
866}
867
868
869BreakEvent.prototype.eventType = function() {
870 return Debug.DebugEvent.Break;
871};
872
873
874BreakEvent.prototype.func = function() {
875 return this.frame_.func();
876};
877
878
879BreakEvent.prototype.sourceLine = function() {
880 return this.frame_.sourceLine();
881};
882
883
884BreakEvent.prototype.sourceColumn = function() {
885 return this.frame_.sourceColumn();
886};
887
888
889BreakEvent.prototype.sourceLineText = function() {
890 return this.frame_.sourceLineText();
891};
892
893
894BreakEvent.prototype.breakPointsHit = function() {
895 return this.break_points_hit_;
896};
897
898
Ben Murdoch014dc512016-03-22 12:00:34 +0000899function MakeExceptionEvent(break_id, exception, uncaught, promise) {
900 return new ExceptionEvent(break_id, exception, uncaught, promise);
901}
902
903
904function ExceptionEvent(break_id, exception, uncaught, promise) {
905 this.exec_state_ = new ExecutionState(break_id);
906 this.exception_ = exception;
907 this.uncaught_ = uncaught;
908 this.promise_ = promise;
909}
910
911
912ExceptionEvent.prototype.eventType = function() {
913 return Debug.DebugEvent.Exception;
914};
915
916
917ExceptionEvent.prototype.exception = function() {
918 return this.exception_;
919};
920
921
922ExceptionEvent.prototype.uncaught = function() {
923 return this.uncaught_;
924};
925
926
927ExceptionEvent.prototype.promise = function() {
928 return this.promise_;
929};
930
931
932ExceptionEvent.prototype.func = function() {
933 return this.exec_state_.frame(0).func();
934};
935
936
937ExceptionEvent.prototype.sourceLine = function() {
938 return this.exec_state_.frame(0).sourceLine();
939};
940
941
942ExceptionEvent.prototype.sourceColumn = function() {
943 return this.exec_state_.frame(0).sourceColumn();
944};
945
946
947ExceptionEvent.prototype.sourceLineText = function() {
948 return this.exec_state_.frame(0).sourceLineText();
949};
950
951
Ben Murdoch014dc512016-03-22 12:00:34 +0000952function MakeCompileEvent(script, type) {
953 return new CompileEvent(script, type);
954}
955
956
957function CompileEvent(script, type) {
958 this.script_ = MakeMirror(script);
959 this.type_ = type;
960}
961
962
963CompileEvent.prototype.eventType = function() {
964 return this.type_;
965};
966
967
968CompileEvent.prototype.script = function() {
969 return this.script_;
970};
971
972
Ben Murdoch014dc512016-03-22 12:00:34 +0000973function MakeScriptObject_(script, include_source) {
974 var o = { id: script.id(),
975 name: script.name(),
976 lineOffset: script.lineOffset(),
977 columnOffset: script.columnOffset(),
978 lineCount: script.lineCount(),
979 };
980 if (!IS_UNDEFINED(script.data())) {
981 o.data = script.data();
982 }
983 if (include_source) {
984 o.source = script.source();
985 }
986 return o;
987}
988
989
Ben Murdoch62ed6312017-06-06 11:06:27 +0100990function MakeAsyncTaskEvent(type, id) {
991 return new AsyncTaskEvent(type, id);
Ben Murdoch014dc512016-03-22 12:00:34 +0000992}
993
994
Ben Murdoch62ed6312017-06-06 11:06:27 +0100995function AsyncTaskEvent(type, id) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000996 this.type_ = type;
997 this.id_ = id;
Ben Murdoch014dc512016-03-22 12:00:34 +0000998}
999
1000
1001AsyncTaskEvent.prototype.type = function() {
1002 return this.type_;
1003}
1004
1005
Ben Murdoch014dc512016-03-22 12:00:34 +00001006AsyncTaskEvent.prototype.id = function() {
1007 return this.id_;
1008}
1009
Ben Murdoch014dc512016-03-22 12:00:34 +00001010// -------------------------------------------------------------------
1011// Exports
1012
1013utils.InstallConstants(global, [
1014 "Debug", Debug,
Ben Murdoch014dc512016-03-22 12:00:34 +00001015 "BreakEvent", BreakEvent,
1016 "CompileEvent", CompileEvent,
1017 "BreakPoint", BreakPoint,
1018]);
1019
1020// Functions needed by the debugger runtime.
1021utils.InstallFunctions(utils, DONT_ENUM, [
1022 "MakeExecutionState", MakeExecutionState,
1023 "MakeExceptionEvent", MakeExceptionEvent,
1024 "MakeBreakEvent", MakeBreakEvent,
1025 "MakeCompileEvent", MakeCompileEvent,
Ben Murdoch014dc512016-03-22 12:00:34 +00001026 "MakeAsyncTaskEvent", MakeAsyncTaskEvent,
1027 "IsBreakPointTriggered", IsBreakPointTriggered,
Ben Murdoch014dc512016-03-22 12:00:34 +00001028]);
1029
Ben Murdoch014dc512016-03-22 12:00:34 +00001030})