Commit 175fc49c authored by Yang Guo's avatar Yang Guo Committed by Commit Bot

[debug] remove legacy implementation for break points.

R=herhut@chromium.org, jgruber@chromium.org

Bug: v8:7310, v8:5510
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Icefd10b6cc210e5bb2684d18b091179ead387326
Reviewed-on: https://chromium-review.googlesource.com/934445
Commit-Queue: Yang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#51552}
parent d504203e
......@@ -180,12 +180,10 @@ class DebugDelegate {
bool is_blackboxed) {}
virtual void ScriptCompiled(v8::Local<Script> script, bool is_live_edited,
bool has_compile_error) {}
// |break_points_hit| contains installed by JS debug API breakpoint objects.
// |inspector_break_points_hit| contains id of breakpoints installed with
// debug::Script::SetBreakpoint API.
virtual void BreakProgramRequested(
v8::Local<v8::Context> paused_context, v8::Local<v8::Object> exec_state,
v8::Local<v8::Value> break_points_hit,
const std::vector<debug::BreakpointId>& inspector_break_points_hit) {}
virtual void ExceptionThrown(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object> exec_state,
......
......@@ -510,9 +510,9 @@ MaybeHandle<FixedArray> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info,
if (has_break_points) *has_break_points = has_break_points_to_check;
if (!has_break_points_to_check) return {};
Handle<Object> break_point_objects =
debug_info->GetBreakPointObjects(location->position());
return Debug::GetHitBreakPointObjects(break_point_objects);
Handle<Object> break_points =
debug_info->GetBreakPoints(location->position());
return Debug::GetHitBreakPoints(break_points);
}
......@@ -567,52 +567,27 @@ MaybeHandle<Object> Debug::CallFunction(const char* name, int argc,
// Check whether a single break point object is triggered.
bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
Factory* factory = isolate_->factory();
bool Debug::CheckBreakPoint(Handle<BreakPoint> break_point) {
HandleScope scope(isolate_);
// TODO(kozyatinskiy): replace this if by DCHEK once the JS debug API has been
// removed.
if (break_point_object->IsBreakPoint()) {
Handle<BreakPoint> break_point =
Handle<BreakPoint>::cast(break_point_object);
if (!break_point->condition()->length()) return true;
Handle<String> condition(break_point->condition());
Handle<Object> result;
// Since we call CheckBreakpoint only for deoptimized frame on top of stack,
// we can use 0 as index of inlined frame.
if (!DebugEvaluate::Local(isolate_, break_frame_id(),
/* inlined_jsframe_index */ 0, condition, false)
.ToHandle(&result)) {
if (isolate_->has_pending_exception()) {
isolate_->clear_pending_exception();
}
return false;
}
return result->BooleanValue();
}
// Ignore check if break point object is not a JSObject.
if (!break_point_object->IsJSObject()) return true;
// Get the break id as an object.
Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
// Call IsBreakPointTriggered.
Handle<Object> argv[] = { break_id, break_point_object };
if (!break_point->condition()->length()) return true;
Handle<String> condition(break_point->condition());
Handle<Object> result;
if (!CallFunction("IsBreakPointTriggered", arraysize(argv), argv)
// Since we call CheckBreakpoint only for deoptimized frame on top of stack,
// we can use 0 as index of inlined frame.
if (!DebugEvaluate::Local(isolate_, break_frame_id(),
/* inlined_jsframe_index */ 0, condition, false)
.ToHandle(&result)) {
if (isolate_->has_pending_exception()) {
isolate_->clear_pending_exception();
}
return false;
}
// Return whether the break point is triggered.
return result->IsTrue(isolate_);
return result->BooleanValue();
}
bool Debug::SetBreakPoint(Handle<JSFunction> function,
Handle<Object> break_point_object,
Handle<BreakPoint> break_point,
int* source_position) {
HandleScope scope(isolate_);
......@@ -626,7 +601,7 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
// Find the break point and change it.
*source_position = FindBreakablePosition(debug_info, *source_position);
DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object);
DebugInfo::SetBreakPoint(debug_info, *source_position, break_point);
// At least one active break point now.
DCHECK_LT(0, debug_info->GetBreakPointCount());
......@@ -638,13 +613,13 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
}
bool Debug::SetBreakPointForScript(Handle<Script> script,
Handle<Object> break_point_object,
Handle<BreakPoint> break_point,
int* source_position) {
if (script->type() == Script::TYPE_WASM) {
Handle<WasmCompiledModule> compiled_module(
WasmCompiledModule::cast(script->wasm_compiled_module()), isolate_);
return WasmCompiledModule::SetBreakPoint(compiled_module, source_position,
break_point_object);
break_point);
}
HandleScope scope(isolate_);
......@@ -674,7 +649,7 @@ bool Debug::SetBreakPointForScript(Handle<Script> script,
if (breakable_position < *source_position) return false;
*source_position = breakable_position;
DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object);
DebugInfo::SetBreakPoint(debug_info, *source_position, break_point);
// At least one active break point now.
DCHECK_LT(0, debug_info->GetBreakPointCount());
......@@ -731,16 +706,16 @@ void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) {
}
}
void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
void Debug::ClearBreakPoint(Handle<BreakPoint> break_point) {
HandleScope scope(isolate_);
for (DebugInfoListNode* node = debug_info_list_; node != nullptr;
node = node->next()) {
Handle<Object> result =
DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object);
DebugInfo::FindBreakPointInfo(node->debug_info(), break_point);
if (result->IsUndefined(isolate_)) continue;
Handle<DebugInfo> debug_info = node->debug_info();
if (DebugInfo::ClearBreakPoint(debug_info, break_point_object)) {
if (DebugInfo::ClearBreakPoint(debug_info, break_point)) {
ClearBreakPoints(debug_info);
if (debug_info->GetBreakPointCount() == 0) {
RemoveBreakInfoAndMaybeFree(debug_info);
......@@ -806,25 +781,24 @@ bool Debug::IsBreakOnException(ExceptionBreakType type) {
}
}
MaybeHandle<FixedArray> Debug::GetHitBreakPointObjects(
Handle<Object> break_point_objects) {
DCHECK(!break_point_objects->IsUndefined(isolate_));
if (!break_point_objects->IsFixedArray()) {
if (!CheckBreakPoint(break_point_objects)) return {};
MaybeHandle<FixedArray> Debug::GetHitBreakPoints(Handle<Object> break_points) {
DCHECK(!break_points->IsUndefined(isolate_));
if (!break_points->IsFixedArray()) {
if (!CheckBreakPoint(Handle<BreakPoint>::cast(break_points))) return {};
Handle<FixedArray> break_points_hit = isolate_->factory()->NewFixedArray(1);
break_points_hit->set(0, *break_point_objects);
break_points_hit->set(0, *break_points);
return break_points_hit;
}
Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
Handle<FixedArray> array(FixedArray::cast(*break_points));
int num_objects = array->length();
Handle<FixedArray> break_points_hit =
isolate_->factory()->NewFixedArray(num_objects);
int break_points_hit_count = 0;
for (int i = 0; i < num_objects; ++i) {
Handle<Object> break_point_object(array->get(i), isolate_);
if (CheckBreakPoint(break_point_object)) {
break_points_hit->set(break_points_hit_count++, *break_point_object);
Handle<Object> break_point(array->get(i), isolate_);
if (CheckBreakPoint(Handle<BreakPoint>::cast(break_point))) {
break_points_hit->set(break_points_hit_count++, *break_point);
}
}
if (break_points_hit_count == 0) return {};
......@@ -1567,14 +1541,6 @@ MaybeHandle<Object> Debug::MakeExecutionState() {
}
MaybeHandle<Object> Debug::MakeBreakEvent(Handle<Object> break_points_hit) {
// Create the new break event object.
Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
break_points_hit };
return CallFunction("MakeBreakEvent", arraysize(argv), argv);
}
MaybeHandle<Object> Debug::MakeExceptionEvent(Handle<Object> exception,
bool uncaught,
Handle<Object> promise) {
......@@ -1750,29 +1716,15 @@ void Debug::OnDebugBreak(Handle<FixedArray> break_points_hit) {
int inspector_break_points_count = 0;
// This array contains breakpoints installed using JS debug API.
for (int i = 0; i < break_points_hit->length(); ++i) {
Object* break_point = break_points_hit->get(i);
if (break_point->IsBreakPoint()) {
inspector_break_points_hit.push_back(BreakPoint::cast(break_point)->id());
++inspector_break_points_count;
} else {
break_points_hit->set(i - inspector_break_points_count, break_point);
}
}
int break_points_length =
break_points_hit->length() - inspector_break_points_count;
Handle<Object> break_points;
if (break_points_length) {
break_points_hit->Shrink(break_points_length);
break_points = isolate_->factory()->NewJSArrayWithElements(
break_points_hit, PACKED_ELEMENTS, break_points_length);
} else {
break_points = isolate_->factory()->undefined_value();
BreakPoint* break_point = BreakPoint::cast(break_points_hit->get(i));
inspector_break_points_hit.push_back(break_point->id());
++inspector_break_points_count;
}
debug_delegate_->BreakProgramRequested(
GetDebugEventContext(isolate_),
v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
v8::Utils::ToLocal(break_points), inspector_break_points_hit);
inspector_break_points_hit);
}
......@@ -2278,16 +2230,9 @@ void LegacyDebugDelegate::ScriptCompiled(v8::Local<v8::debug::Script> script,
void LegacyDebugDelegate::BreakProgramRequested(
v8::Local<v8::Context> paused_context, v8::Local<v8::Object> exec_state,
v8::Local<v8::Value> break_points_hit,
const std::vector<debug::BreakpointId>&) {
Handle<Object> event_data;
if (isolate_->debug()
->MakeBreakEvent(v8::Utils::OpenHandle(*break_points_hit))
.ToHandle(&event_data)) {
ProcessDebugEvent(
v8::Break, Handle<JSObject>::cast(event_data),
Handle<JSObject>::cast(v8::Utils::OpenHandle(*exec_state)));
}
ProcessDebugEvent(v8::Break, isolate_->factory()->NewJSObjectWithNullProto(),
Handle<JSObject>::cast(v8::Utils::OpenHandle(*exec_state)));
}
void LegacyDebugDelegate::ExceptionThrown(v8::Local<v8::Context> paused_context,
......@@ -2314,32 +2259,6 @@ void LegacyDebugDelegate::ProcessDebugEvent(v8::DebugEvent event,
}
}
JavaScriptDebugDelegate::JavaScriptDebugDelegate(Isolate* isolate,
Handle<JSFunction> listener,
Handle<Object> data)
: LegacyDebugDelegate(isolate) {
GlobalHandles* global_handles = isolate->global_handles();
listener_ = global_handles->Create(*listener);
data_ = global_handles->Create(*data);
}
JavaScriptDebugDelegate::~JavaScriptDebugDelegate() {
GlobalHandles::Destroy(Handle<Object>::cast(listener_).location());
GlobalHandles::Destroy(data_.location());
}
void JavaScriptDebugDelegate::ProcessDebugEvent(v8::DebugEvent event,
Handle<JSObject> event_data,
Handle<JSObject> exec_state) {
AllowJavascriptExecutionDebugOnly allow_script(isolate_);
Handle<Object> argv[] = {Handle<Object>(Smi::FromInt(event), isolate_),
exec_state, event_data, data_};
Handle<JSReceiver> global = isolate_->global_proxy();
// Listener must not throw.
Execution::Call(isolate_, listener_, global, arraysize(argv), argv)
.ToHandleChecked();
}
NativeDebugDelegate::NativeDebugDelegate(Isolate* isolate,
v8::Debug::EventCallback callback,
Handle<Object> data)
......
......@@ -241,12 +241,11 @@ class Debug {
// Break point handling.
bool SetBreakPoint(Handle<JSFunction> function,
Handle<Object> break_point_object,
int* source_position);
Handle<BreakPoint> break_point, int* source_position);
bool SetBreakPointForScript(Handle<Script> script,
Handle<Object> break_point_object,
Handle<BreakPoint> break_point,
int* source_position);
void ClearBreakPoint(Handle<Object> break_point_object);
void ClearBreakPoint(Handle<BreakPoint> break_point);
void ChangeBreakOnException(ExceptionBreakType type, bool enable);
bool IsBreakOnException(ExceptionBreakType type);
......@@ -254,12 +253,11 @@ class Debug {
int* offset, int* id);
void RemoveBreakpoint(int id);
// The parameter is either a BreakPointInfo object, or a FixedArray of
// BreakPointInfo objects.
// The parameter is either a BreakPoint object, or a FixedArray of
// BreakPoint objects.
// Returns an empty handle if no breakpoint is hit, or a FixedArray with all
// hit breakpoints.
MaybeHandle<FixedArray> GetHitBreakPointObjects(
Handle<Object> break_point_objects);
// hit BreakPoint objects.
MaybeHandle<FixedArray> GetHitBreakPoints(Handle<Object> break_points);
// Stepping handling.
void PrepareStep(StepAction step_action);
......@@ -437,8 +435,6 @@ class Debug {
// Constructors for debug event objects.
MUST_USE_RESULT MaybeHandle<Object> MakeExecutionState();
MUST_USE_RESULT MaybeHandle<Object> MakeBreakEvent(
Handle<Object> break_points_hit);
MUST_USE_RESULT MaybeHandle<Object> MakeExceptionEvent(
Handle<Object> exception,
bool uncaught,
......@@ -472,7 +468,7 @@ class Debug {
BreakLocation* location,
bool* has_break_points = nullptr);
bool IsMutedAtCurrentLocation(JavaScriptFrame* frame);
bool CheckBreakPoint(Handle<Object> break_point_object);
bool CheckBreakPoint(Handle<BreakPoint> break_point);
MaybeHandle<Object> CallFunction(const char* name, int argc,
Handle<Object> args[],
bool catch_exceptions = true);
......@@ -604,7 +600,6 @@ class LegacyDebugDelegate : public v8::debug::DebugDelegate {
bool has_compile_error) override;
void BreakProgramRequested(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object> exec_state,
v8::Local<v8::Value> break_points_hit,
const std::vector<debug::BreakpointId>&) override;
void ExceptionThrown(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object> exec_state,
......@@ -626,20 +621,6 @@ class LegacyDebugDelegate : public v8::debug::DebugDelegate {
Handle<JSObject> exec_state) = 0;
};
class JavaScriptDebugDelegate : public LegacyDebugDelegate {
public:
JavaScriptDebugDelegate(Isolate* isolate, Handle<JSFunction> listener,
Handle<Object> data);
virtual ~JavaScriptDebugDelegate();
private:
void ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data,
Handle<JSObject> exec_state) override;
Handle<JSFunction> listener_;
Handle<Object> data_;
};
class NativeDebugDelegate : public LegacyDebugDelegate {
public:
NativeDebugDelegate(Isolate* isolate, v8::Debug::EventCallback callback,
......
......@@ -19,16 +19,8 @@ var ValueMirror = global.ValueMirror;
//----------------------------------------------------------------------------
// Default number of frames to include in the response to backtrace request.
var kDefaultBacktraceLength = 10;
var Debug = {};
// Regular expression to skip "crud" at the beginning of a source line which is
// not really code. Currently the regular expression matches whitespace and
// comments.
var sourceLineBeginningSkip = /^(?:\s*(?:\/\*.*?\*\/)*)*/;
// Debug events which can occur in the V8 JavaScript engine. These originate
// from the API include file debug.h.
Debug.DebugEvent = { Break: 1,
......@@ -58,29 +50,12 @@ Debug.ScriptCompilationType = { Host: 0,
Eval: 1,
JSON: 2 };
// The different script break point types.
Debug.ScriptBreakPointType = { ScriptId: 0,
ScriptName: 1,
ScriptRegExp: 2 };
function ScriptTypeFlag(type) {
return (1 << type);
}
// Globals.
var next_response_seq = 0;
var next_break_point_number = 1;
var break_points = [];
var script_break_points = [];
var debugger_flags = {
breakPointsActive: {
value: true,
getValue: function() { return this.value; },
setValue: function(value) {
this.value = !!value;
%SetBreakPointsActive(this.value);
}
},
breakOnCaughtException: {
getValue: function() { return Debug.isBreakOnException(); },
setValue: function(value) {
......@@ -104,308 +79,6 @@ var debugger_flags = {
};
// Create a new break point object and add it to the list of break points.
function MakeBreakPoint(source_position, opt_script_break_point) {
var break_point = new BreakPoint(source_position, opt_script_break_point);
break_points.push(break_point);
return break_point;
}
// Object representing a break point.
// NOTE: This object does not have a reference to the function having break
// point as this would cause function not to be garbage collected when it is
// not used any more. We do not want break points to keep functions alive.
function BreakPoint(source_position, opt_script_break_point) {
this.source_position_ = source_position;
if (opt_script_break_point) {
this.script_break_point_ = opt_script_break_point;
} else {
this.number_ = next_break_point_number++;
}
this.active_ = true;
this.condition_ = null;
}
BreakPoint.prototype.number = function() {
return this.number_;
};
BreakPoint.prototype.func = function() {
return this.func_;
};
BreakPoint.prototype.source_position = function() {
return this.source_position_;
};
BreakPoint.prototype.active = function() {
if (this.script_break_point()) {
return this.script_break_point().active();
}
return this.active_;
};
BreakPoint.prototype.condition = function() {
if (this.script_break_point() && this.script_break_point().condition()) {
return this.script_break_point().condition();
}
return this.condition_;
};
BreakPoint.prototype.script_break_point = function() {
return this.script_break_point_;
};
BreakPoint.prototype.enable = function() {
this.active_ = true;
};
BreakPoint.prototype.disable = function() {
this.active_ = false;
};
BreakPoint.prototype.setCondition = function(condition) {
this.condition_ = condition;
};
BreakPoint.prototype.isTriggered = function(exec_state) {
// Break point not active - not triggered.
if (!this.active()) return false;
// Check for conditional break point.
if (this.condition()) {
// If break point has condition try to evaluate it in the top frame.
try {
var mirror = exec_state.frame(0).evaluate(this.condition());
// If no sensible mirror or non true value break point not triggered.
if (!(mirror instanceof ValueMirror) || !mirror.value_) {
return false;
}
} catch (e) {
// Exception evaluating condition counts as not triggered.
return false;
}
}
// Break point triggered.
return true;
};
// Function called from the runtime when a break point is hit. Returns true if
// the break point is triggered and supposed to break execution.
function IsBreakPointTriggered(break_id, break_point) {
return break_point.isTriggered(MakeExecutionState(break_id));
}
// Object representing a script break point. The script is referenced by its
// script name or script id and the break point is represented as line and
// column.
function ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
opt_groupId) {
this.type_ = type;
if (type == Debug.ScriptBreakPointType.ScriptId) {
this.script_id_ = script_id_or_name;
} else if (type == Debug.ScriptBreakPointType.ScriptName) {
this.script_name_ = script_id_or_name;
} else if (type == Debug.ScriptBreakPointType.ScriptRegExp) {
this.script_regexp_object_ = new GlobalRegExp(script_id_or_name);
} else {
throw %make_error(kDebugger, "Unexpected breakpoint type " + type);
}
this.line_ = opt_line || 0;
this.column_ = opt_column;
this.groupId_ = opt_groupId;
this.active_ = true;
this.condition_ = null;
this.break_points_ = [];
}
ScriptBreakPoint.prototype.number = function() {
return this.number_;
};
ScriptBreakPoint.prototype.groupId = function() {
return this.groupId_;
};
ScriptBreakPoint.prototype.type = function() {
return this.type_;
};
ScriptBreakPoint.prototype.script_id = function() {
return this.script_id_;
};
ScriptBreakPoint.prototype.script_name = function() {
return this.script_name_;
};
ScriptBreakPoint.prototype.script_regexp_object = function() {
return this.script_regexp_object_;
};
ScriptBreakPoint.prototype.line = function() {
return this.line_;
};
ScriptBreakPoint.prototype.column = function() {
return this.column_;
};
ScriptBreakPoint.prototype.actual_locations = function() {
var locations = [];
for (var i = 0; i < this.break_points_.length; i++) {
locations.push(this.break_points_[i].actual_location);
}
return locations;
};
ScriptBreakPoint.prototype.update_positions = function(line, column) {
this.line_ = line;
this.column_ = column;
};
ScriptBreakPoint.prototype.active = function() {
return this.active_;
};
ScriptBreakPoint.prototype.condition = function() {
return this.condition_;
};
ScriptBreakPoint.prototype.enable = function() {
this.active_ = true;
};
ScriptBreakPoint.prototype.disable = function() {
this.active_ = false;
};
ScriptBreakPoint.prototype.setCondition = function(condition) {
this.condition_ = condition;
};
// Check whether a script matches this script break point. Currently this is
// only based on script name.
ScriptBreakPoint.prototype.matchesScript = function(script) {
if (this.type_ == Debug.ScriptBreakPointType.ScriptId) {
return this.script_id_ == script.id;
} else {
// We might want to account columns here as well.
if (!(script.line_offset <= this.line_ &&
this.line_ < script.line_offset + %ScriptLineCount(script))) {
return false;
}
if (this.type_ == Debug.ScriptBreakPointType.ScriptName) {
return this.script_name_ == script.nameOrSourceURL();
} else if (this.type_ == Debug.ScriptBreakPointType.ScriptRegExp) {
return this.script_regexp_object_.test(script.nameOrSourceURL());
} else {
throw %make_error(kDebugger, "Unexpected breakpoint type " + this.type_);
}
}
};
// Set the script break point in a script.
ScriptBreakPoint.prototype.set = function (script) {
var column = this.column();
var line = this.line();
// If the column is undefined the break is on the line. To help locate the
// first piece of breakable code on the line try to find the column on the
// line which contains some source.
if (IS_UNDEFINED(column)) {
var source_line = %ScriptSourceLine(script, line || script.line_offset);
// Allocate array for caching the columns where the actual source starts.
if (!script.sourceColumnStart_) {
script.sourceColumnStart_ = new GlobalArray(%ScriptLineCount(script));
}
// Fill cache if needed and get column where the actual source starts.
if (IS_UNDEFINED(script.sourceColumnStart_[line])) {
script.sourceColumnStart_[line] =
source_line.match(sourceLineBeginningSkip)[0].length;
}
column = script.sourceColumnStart_[line];
}
// Convert the line and column into an absolute position within the script.
var position = Debug.findScriptSourcePosition(script, this.line(), column);
// If the position is not found in the script (the script might be shorter
// than it used to be) just ignore it.
if (IS_NULL(position)) return;
// Create a break point object and set the break point.
var break_point = MakeBreakPoint(position, this);
var actual_position = %SetScriptBreakPoint(script, position,
break_point);
if (IS_UNDEFINED(actual_position)) {
actual_position = position;
}
var actual_location = script.locationFromPosition(actual_position, true);
break_point.actual_location = { line: actual_location.line,
column: actual_location.column,
script_id: script.id };
this.break_points_.push(break_point);
return break_point;
};
// Clear all the break points created from this script break point
ScriptBreakPoint.prototype.clear = function () {
var remaining_break_points = [];
for (var i = 0; i < break_points.length; i++) {
if (break_points[i].script_break_point() &&
break_points[i].script_break_point() === this) {
%ClearBreakPoint(break_points[i]);
} else {
remaining_break_points.push(break_points[i]);
}
}
break_points = remaining_break_points;
this.break_points_ = [];
};
Debug.setListener = function(listener, opt_data) {
if (!IS_FUNCTION(listener) && !IS_UNDEFINED(listener) && !IS_NULL(listener)) {
throw %make_type_error(kDebuggerType);
}
%SetDebugEventListener(listener, opt_data);
};
// Returns a Script object. If the parameter is a function the return value
// is the script in which the function is defined. If the parameter is a string
// the return value is the script for which the script name has that string
......@@ -475,246 +148,6 @@ Debug.findScriptSourcePosition = function(script, opt_line, opt_column) {
return location ? location.position : null;
};
Debug.findBreakPoint = function(break_point_number, remove) {
var break_point;
for (var i = 0; i < break_points.length; i++) {
if (break_points[i].number() == break_point_number) {
break_point = break_points[i];
// Remove the break point from the list if requested.
if (remove) {
break_points.splice(i, 1);
}
break;
}
}
if (break_point) {
return break_point;
} else {
return this.findScriptBreakPoint(break_point_number, remove);
}
};
Debug.findBreakPointActualLocations = function(break_point_number) {
for (var i = 0; i < script_break_points.length; i++) {
if (script_break_points[i].number() == break_point_number) {
return script_break_points[i].actual_locations();
}
}
for (var i = 0; i < break_points.length; i++) {
if (break_points[i].number() == break_point_number) {
return [break_points[i].actual_location];
}
}
return [];
};
Debug.setBreakPoint = function(func, opt_line, opt_column, opt_condition) {
if (!IS_FUNCTION(func)) throw %make_type_error(kDebuggerType);
// Break points in API functions are not supported.
if (%FunctionIsAPIFunction(func)) {
throw %make_error(kDebugger, 'Cannot set break point in native code.');
}
// Find source position.
var source_position =
this.findFunctionSourceLocation(func, opt_line, opt_column).position;
// Find the script for the function.
var script = %FunctionGetScript(func);
// Break in builtin JavaScript code is not supported.
if (script.type == Debug.ScriptType.Native) {
throw %make_error(kDebugger, 'Cannot set break point in native code.');
}
// If the script for the function has a name convert this to a script break
// point.
if (script && script.id) {
// Find line and column for the position in the script and set a script
// break point from that.
var location = script.locationFromPosition(source_position, false);
return this.setScriptBreakPointById(script.id,
location.line, location.column,
opt_condition);
} else {
// Set a break point directly on the function.
var break_point = MakeBreakPoint(source_position);
var actual_position =
%SetFunctionBreakPoint(func, source_position, break_point);
var actual_location = script.locationFromPosition(actual_position, true);
break_point.actual_location = { line: actual_location.line,
column: actual_location.column,
script_id: script.id };
break_point.setCondition(opt_condition);
return break_point.number();
}
};
Debug.setBreakPointByScriptIdAndPosition = function(script_id, position,
condition, enabled)
{
var break_point = MakeBreakPoint(position);
break_point.setCondition(condition);
if (!enabled) {
break_point.disable();
}
var script = scriptById(script_id);
if (script) {
break_point.actual_position = %SetScriptBreakPoint(script, position, break_point);
}
return break_point;
};
Debug.enableBreakPoint = function(break_point_number) {
var break_point = this.findBreakPoint(break_point_number, false);
// Only enable if the breakpoint hasn't been deleted:
if (break_point) {
break_point.enable();
}
};
Debug.disableBreakPoint = function(break_point_number) {
var break_point = this.findBreakPoint(break_point_number, false);
// Only enable if the breakpoint hasn't been deleted:
if (break_point) {
break_point.disable();
}
};
Debug.changeBreakPointCondition = function(break_point_number, condition) {
var break_point = this.findBreakPoint(break_point_number, false);
break_point.setCondition(condition);
};
Debug.clearBreakPoint = function(break_point_number) {
var break_point = this.findBreakPoint(break_point_number, true);
if (break_point) {
return %ClearBreakPoint(break_point);
} else {
break_point = this.findScriptBreakPoint(break_point_number, true);
if (!break_point) throw %make_error(kDebugger, 'Invalid breakpoint');
}
};
Debug.clearAllBreakPoints = function() {
for (var i = 0; i < break_points.length; i++) {
var break_point = break_points[i];
%ClearBreakPoint(break_point);
}
break_points = [];
};
Debug.disableAllBreakPoints = function() {
// Disable all user defined breakpoints:
for (var i = 1; i < next_break_point_number; i++) {
Debug.disableBreakPoint(i);
}
// Disable all exception breakpoints:
%ChangeBreakOnException(Debug.ExceptionBreak.Caught, false);
%ChangeBreakOnException(Debug.ExceptionBreak.Uncaught, false);
};
Debug.findScriptBreakPoint = function(break_point_number, remove) {
var script_break_point;
for (var i = 0; i < script_break_points.length; i++) {
if (script_break_points[i].number() == break_point_number) {
script_break_point = script_break_points[i];
// Remove the break point from the list if requested.
if (remove) {
script_break_point.clear();
script_break_points.splice(i,1);
}
break;
}
}
return script_break_point;
};
// Sets a breakpoint in a script identified through id or name at the
// specified source line and column within that line.
Debug.setScriptBreakPoint = function(type, script_id_or_name,
opt_line, opt_column, opt_condition,
opt_groupId) {
// Create script break point object.
var script_break_point =
new ScriptBreakPoint(type, script_id_or_name, opt_line, opt_column,
opt_groupId);
// Assign number to the new script break point and add it.
script_break_point.number_ = next_break_point_number++;
script_break_point.setCondition(opt_condition);
script_break_points.push(script_break_point);
// Run through all scripts to see if this script break point matches any
// loaded scripts.
var scripts = this.scripts();
for (var i = 0; i < scripts.length; i++) {
if (script_break_point.matchesScript(scripts[i])) {
script_break_point.set(scripts[i]);
}
}
return script_break_point.number();
};
Debug.setScriptBreakPointById = function(script_id,
opt_line, opt_column,
opt_condition, opt_groupId) {
return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptId,
script_id, opt_line, opt_column,
opt_condition, opt_groupId);
};
Debug.setScriptBreakPointByName = function(script_name,
opt_line, opt_column,
opt_condition, opt_groupId) {
return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptName,
script_name, opt_line, opt_column,
opt_condition, opt_groupId);
};
Debug.setScriptBreakPointByRegExp = function(script_regexp,
opt_line, opt_column,
opt_condition, opt_groupId) {
return this.setScriptBreakPoint(Debug.ScriptBreakPointType.ScriptRegExp,
script_regexp, opt_line, opt_column,
opt_condition, opt_groupId);
};
Debug.enableScriptBreakPoint = function(break_point_number) {
var script_break_point = this.findScriptBreakPoint(break_point_number, false);
script_break_point.enable();
};
Debug.disableScriptBreakPoint = function(break_point_number) {
var script_break_point = this.findScriptBreakPoint(break_point_number, false);
script_break_point.disable();
};
Debug.changeScriptBreakPointCondition = function(
break_point_number, condition) {
var script_break_point = this.findScriptBreakPoint(break_point_number, false);
script_break_point.setCondition(condition);
};
Debug.scriptBreakPoints = function() {
return script_break_points;
};
Debug.clearStepping = function() {
%ClearStepping();
};
......@@ -743,28 +176,6 @@ Debug.isBreakOnUncaughtException = function() {
return !!%IsBreakOnException(Debug.ExceptionBreak.Uncaught);
};
Debug.showBreakPoints = function(f, full) {
if (!IS_FUNCTION(f)) throw %make_error(kDebuggerType);
var source = full ? this.scriptSource(f) : this.source(f);
var offset = full ? 0 : this.sourcePosition(f);
var locations = %GetBreakLocations(f);
if (!locations) return source;
locations.sort(function(x, y) { return x - y; });
var result = "";
var prev_pos = 0;
var pos;
for (var i = 0; i < locations.length; i++) {
pos = locations[i] - offset;
result += source.slice(prev_pos, pos);
result += "[B" + i + "]";
prev_pos = pos;
}
pos = source.length;
result += source.substring(prev_pos, pos);
return result;
};
// Get all the scripts currently loaded. Locating all the scripts is based on
// scanning the heap.
Debug.scripts = function() {
......@@ -837,46 +248,6 @@ ExecutionState.prototype.selectedFrame = function() {
return this.selected_frame;
};
function MakeBreakEvent(break_id, break_points_hit) {
return new BreakEvent(break_id, break_points_hit);
}
function BreakEvent(break_id, break_points_hit) {
this.frame_ = new FrameMirror(break_id, 0);
this.break_points_hit_ = break_points_hit;
}
BreakEvent.prototype.eventType = function() {
return Debug.DebugEvent.Break;
};
BreakEvent.prototype.func = function() {
return this.frame_.func();
};
BreakEvent.prototype.sourceLine = function() {
return this.frame_.sourceLine();
};
BreakEvent.prototype.sourceColumn = function() {
return this.frame_.sourceColumn();
};
BreakEvent.prototype.sourceLineText = function() {
return this.frame_.sourceLineText();
};
BreakEvent.prototype.breakPointsHit = function() {
return this.break_points_hit_;
};
function MakeExceptionEvent(break_id, exception, uncaught, promise) {
return new ExceptionEvent(break_id, exception, uncaught, promise);
......@@ -994,19 +365,15 @@ AsyncTaskEvent.prototype.id = function() {
utils.InstallConstants(global, [
"Debug", Debug,
"BreakEvent", BreakEvent,
"CompileEvent", CompileEvent,
"BreakPoint", BreakPoint,
]);
// Functions needed by the debugger runtime.
utils.InstallConstants(utils, [
"MakeExecutionState", MakeExecutionState,
"MakeExceptionEvent", MakeExceptionEvent,
"MakeBreakEvent", MakeBreakEvent,
"MakeCompileEvent", MakeCompileEvent,
"MakeAsyncTaskEvent", MakeAsyncTaskEvent,
"IsBreakPointTriggered", IsBreakPointTriggered,
]);
})
......@@ -2717,7 +2717,7 @@ Handle<BreakPointInfo> Factory::NewBreakPointInfo(int source_position) {
Handle<BreakPointInfo> new_break_point_info =
Handle<BreakPointInfo>::cast(NewStruct(TUPLE2_TYPE, TENURED));
new_break_point_info->set_source_position(source_position);
new_break_point_info->set_break_point_objects(*undefined_value());
new_break_point_info->set_break_points(*undefined_value());
return new_break_point_info;
}
......
......@@ -494,7 +494,6 @@ void V8Debugger::ScriptCompiled(v8::Local<v8::debug::Script> script,
void V8Debugger::BreakProgramRequested(
v8::Local<v8::Context> pausedContext, v8::Local<v8::Object>,
v8::Local<v8::Value>,
const std::vector<v8::debug::BreakpointId>& break_points_hit) {
handleProgramBreak(pausedContext, v8::Local<v8::Value>(), break_points_hit);
}
......
......@@ -169,7 +169,6 @@ class V8Debugger : public v8::debug::DebugDelegate {
bool has_compile_error) override;
void BreakProgramRequested(
v8::Local<v8::Context> paused_context, v8::Local<v8::Object>,
v8::Local<v8::Value>,
const std::vector<v8::debug::BreakpointId>& break_points_hit) override;
void ExceptionThrown(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object>, v8::Local<v8::Value> exception,
......
......@@ -28,7 +28,7 @@ ACCESSORS(DebugInfo, break_points, FixedArray, kBreakPointsStateOffset)
ACCESSORS(DebugInfo, coverage_info, Object, kCoverageInfoOffset)
SMI_ACCESSORS(BreakPointInfo, source_position, kSourcePositionOffset)
ACCESSORS(BreakPointInfo, break_point_objects, Object, kBreakPointObjectsOffset)
ACCESSORS(BreakPointInfo, break_points, Object, kBreakPointsOffset)
SMI_ACCESSORS(BreakPoint, id, kIdOffset)
ACCESSORS(BreakPoint, condition, String, kConditionOffset)
......
......@@ -76,7 +76,7 @@ Object* DebugInfo::GetBreakPointInfo(int source_position) {
}
bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
Handle<Object> break_point_object) {
Handle<BreakPoint> break_point) {
DCHECK(debug_info->HasBreakInfo());
Isolate* isolate = debug_info->GetIsolate();
......@@ -84,9 +84,8 @@ bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
if (debug_info->break_points()->get(i)->IsUndefined(isolate)) continue;
Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
if (BreakPointInfo::HasBreakPointObject(break_point_info,
break_point_object)) {
BreakPointInfo::ClearBreakPoint(break_point_info, break_point_object);
if (BreakPointInfo::HasBreakPoint(break_point_info, break_point)) {
BreakPointInfo::ClearBreakPoint(break_point_info, break_point);
return true;
}
}
......@@ -94,14 +93,14 @@ bool DebugInfo::ClearBreakPoint(Handle<DebugInfo> debug_info,
}
void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
Handle<Object> break_point_object) {
Handle<BreakPoint> break_point) {
DCHECK(debug_info->HasBreakInfo());
Isolate* isolate = debug_info->GetIsolate();
Handle<Object> break_point_info(
debug_info->GetBreakPointInfo(source_position), isolate);
if (!break_point_info->IsUndefined(isolate)) {
BreakPointInfo::SetBreakPoint(
Handle<BreakPointInfo>::cast(break_point_info), break_point_object);
Handle<BreakPointInfo>::cast(break_point_info), break_point);
return;
}
......@@ -117,8 +116,8 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
}
if (index == kNoBreakPointInfo) {
// No free slot - extend break point info array.
Handle<FixedArray> old_break_points = Handle<FixedArray>(
FixedArray::cast(debug_info->break_points()), isolate);
Handle<FixedArray> old_break_points =
Handle<FixedArray>(debug_info->break_points(), isolate);
Handle<FixedArray> new_break_points = isolate->factory()->NewFixedArray(
old_break_points->length() +
DebugInfo::kEstimatedNofBreakPointsInFunction);
......@@ -134,20 +133,20 @@ void DebugInfo::SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
// Allocate new BreakPointInfo object and set the break point.
Handle<BreakPointInfo> new_break_point_info =
isolate->factory()->NewBreakPointInfo(source_position);
BreakPointInfo::SetBreakPoint(new_break_point_info, break_point_object);
BreakPointInfo::SetBreakPoint(new_break_point_info, break_point);
debug_info->break_points()->set(index, *new_break_point_info);
}
// Get the break point objects for a source position.
Handle<Object> DebugInfo::GetBreakPointObjects(int source_position) {
Handle<Object> DebugInfo::GetBreakPoints(int source_position) {
DCHECK(HasBreakInfo());
Object* break_point_info = GetBreakPointInfo(source_position);
Isolate* isolate = GetIsolate();
if (break_point_info->IsUndefined(isolate)) {
return isolate->factory()->undefined_value();
}
return Handle<Object>(
BreakPointInfo::cast(break_point_info)->break_point_objects(), isolate);
return Handle<Object>(BreakPointInfo::cast(break_point_info)->break_points(),
isolate);
}
// Get the total number of break points.
......@@ -165,16 +164,15 @@ int DebugInfo::GetBreakPointCount() {
return count;
}
Handle<Object> DebugInfo::FindBreakPointInfo(
Handle<DebugInfo> debug_info, Handle<Object> break_point_object) {
Handle<Object> DebugInfo::FindBreakPointInfo(Handle<DebugInfo> debug_info,
Handle<BreakPoint> break_point) {
DCHECK(debug_info->HasBreakInfo());
Isolate* isolate = debug_info->GetIsolate();
for (int i = 0; i < debug_info->break_points()->length(); i++) {
if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) {
Handle<BreakPointInfo> break_point_info = Handle<BreakPointInfo>(
BreakPointInfo::cast(debug_info->break_points()->get(i)), isolate);
if (BreakPointInfo::HasBreakPointObject(break_point_info,
break_point_object)) {
if (BreakPointInfo::HasBreakPoint(break_point_info, break_point)) {
return break_point_info;
}
}
......@@ -199,40 +197,34 @@ bool DebugInfo::ClearCoverageInfo() {
}
namespace {
bool IsEqual(Object* break_point1, Object* break_point2) {
// TODO(kozyatinskiy): remove non-BreakPoint logic once the JS debug API has
// been removed.
if (break_point1->IsBreakPoint() != break_point2->IsBreakPoint())
return false;
if (!break_point1->IsBreakPoint()) return break_point1 == break_point2;
return BreakPoint::cast(break_point1)->id() ==
BreakPoint::cast(break_point2)->id();
bool IsEqual(BreakPoint* break_point1, BreakPoint* break_point2) {
return break_point1->id() == break_point2->id();
}
} // namespace
// Remove the specified break point object.
void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
Handle<Object> break_point_object) {
Handle<BreakPoint> break_point) {
Isolate* isolate = break_point_info->GetIsolate();
// If there are no break points just ignore.
if (break_point_info->break_point_objects()->IsUndefined(isolate)) return;
if (break_point_info->break_points()->IsUndefined(isolate)) return;
// If there is a single break point clear it if it is the same.
if (!break_point_info->break_point_objects()->IsFixedArray()) {
if (IsEqual(break_point_info->break_point_objects(), *break_point_object)) {
break_point_info->set_break_point_objects(
isolate->heap()->undefined_value());
if (!break_point_info->break_points()->IsFixedArray()) {
if (IsEqual(BreakPoint::cast(break_point_info->break_points()),
*break_point)) {
break_point_info->set_break_points(isolate->heap()->undefined_value());
}
return;
}
// If there are multiple break points shrink the array
DCHECK(break_point_info->break_point_objects()->IsFixedArray());
Handle<FixedArray> old_array = Handle<FixedArray>(
FixedArray::cast(break_point_info->break_point_objects()));
DCHECK(break_point_info->break_points()->IsFixedArray());
Handle<FixedArray> old_array =
Handle<FixedArray>(FixedArray::cast(break_point_info->break_points()));
Handle<FixedArray> new_array =
isolate->factory()->NewFixedArray(old_array->length() - 1);
int found_count = 0;
for (int i = 0; i < old_array->length(); i++) {
if (IsEqual(old_array->get(i), *break_point_object)) {
if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) {
DCHECK_EQ(found_count, 0);
found_count++;
} else {
......@@ -240,61 +232,60 @@ void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
}
}
// If the break point was found in the list change it.
if (found_count > 0) break_point_info->set_break_point_objects(*new_array);
if (found_count > 0) break_point_info->set_break_points(*new_array);
}
// Add the specified break point object.
void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
Handle<Object> break_point_object) {
Handle<BreakPoint> break_point) {
Isolate* isolate = break_point_info->GetIsolate();
// If there was no break point objects before just set it.
if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
break_point_info->set_break_point_objects(*break_point_object);
if (break_point_info->break_points()->IsUndefined(isolate)) {
break_point_info->set_break_points(*break_point);
return;
}
// If the break point object is the same as before just ignore.
if (break_point_info->break_point_objects() == *break_point_object) return;
if (break_point_info->break_points() == *break_point) return;
// If there was one break point object before replace with array.
if (!break_point_info->break_point_objects()->IsFixedArray()) {
if (!break_point_info->break_points()->IsFixedArray()) {
Handle<FixedArray> array = isolate->factory()->NewFixedArray(2);
array->set(0, break_point_info->break_point_objects());
array->set(1, *break_point_object);
break_point_info->set_break_point_objects(*array);
array->set(0, break_point_info->break_points());
array->set(1, *break_point);
break_point_info->set_break_points(*array);
return;
}
// If there was more than one break point before extend array.
Handle<FixedArray> old_array = Handle<FixedArray>(
FixedArray::cast(break_point_info->break_point_objects()));
Handle<FixedArray> old_array =
Handle<FixedArray>(FixedArray::cast(break_point_info->break_points()));
Handle<FixedArray> new_array =
isolate->factory()->NewFixedArray(old_array->length() + 1);
for (int i = 0; i < old_array->length(); i++) {
// If the break point was there before just ignore.
if (IsEqual(old_array->get(i), *break_point_object)) return;
if (IsEqual(BreakPoint::cast(old_array->get(i)), *break_point)) return;
new_array->set(i, old_array->get(i));
}
// Add the new break point.
new_array->set(old_array->length(), *break_point_object);
break_point_info->set_break_point_objects(*new_array);
new_array->set(old_array->length(), *break_point);
break_point_info->set_break_points(*new_array);
}
bool BreakPointInfo::HasBreakPointObject(
Handle<BreakPointInfo> break_point_info,
Handle<Object> break_point_object) {
bool BreakPointInfo::HasBreakPoint(Handle<BreakPointInfo> break_point_info,
Handle<BreakPoint> break_point) {
// No break point.
Isolate* isolate = break_point_info->GetIsolate();
if (break_point_info->break_point_objects()->IsUndefined(isolate)) {
if (break_point_info->break_points()->IsUndefined(isolate)) {
return false;
}
// Single break point.
if (!break_point_info->break_point_objects()->IsFixedArray()) {
return IsEqual(break_point_info->break_point_objects(),
*break_point_object);
if (!break_point_info->break_points()->IsFixedArray()) {
return IsEqual(BreakPoint::cast(break_point_info->break_points()),
*break_point);
}
// Multiple break points.
FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
FixedArray* array = FixedArray::cast(break_point_info->break_points());
for (int i = 0; i < array->length(); i++) {
if (IsEqual(array->get(i), *break_point_object)) {
if (IsEqual(BreakPoint::cast(array->get(i)), *break_point)) {
return true;
}
}
......@@ -304,11 +295,11 @@ bool BreakPointInfo::HasBreakPointObject(
// Get the number of break points.
int BreakPointInfo::GetBreakPointCount() {
// No break point.
if (break_point_objects()->IsUndefined(GetIsolate())) return 0;
if (break_points()->IsUndefined(GetIsolate())) return 0;
// Single break point.
if (!break_point_objects()->IsFixedArray()) return 1;
if (!break_points()->IsFixedArray()) return 1;
// Multiple break points.
return FixedArray::cast(break_point_objects())->length();
return FixedArray::cast(break_points())->length();
}
int CoverageInfo::SlotCount() const {
......
......@@ -14,6 +14,7 @@
namespace v8 {
namespace internal {
class BreakPoint;
class BytecodeArray;
// The DebugInfo class holds additional information for a function being
......@@ -69,15 +70,15 @@ class DebugInfo : public Struct {
bool HasBreakPoint(int source_position);
// Attempt to clear a break point. Return true if successful.
static bool ClearBreakPoint(Handle<DebugInfo> debug_info,
Handle<Object> break_point_object);
Handle<BreakPoint> break_point);
// Set a break point.
static void SetBreakPoint(Handle<DebugInfo> debug_info, int source_position,
Handle<Object> break_point_object);
Handle<BreakPoint> break_point);
// Get the break point objects for a source position.
Handle<Object> GetBreakPointObjects(int source_position);
Handle<Object> GetBreakPoints(int source_position);
// Find the break point info holding this break point object.
static Handle<Object> FindBreakPointInfo(Handle<DebugInfo> debug_info,
Handle<Object> break_point_object);
Handle<BreakPoint> break_point);
// Get the number of break points for this function.
int GetBreakPointCount();
......@@ -134,17 +135,17 @@ class BreakPointInfo : public Tuple2 {
// The position in the source for the break position.
DECL_INT_ACCESSORS(source_position)
// List of related JavaScript break points.
DECL_ACCESSORS(break_point_objects, Object)
DECL_ACCESSORS(break_points, Object)
// Removes a break point.
static void ClearBreakPoint(Handle<BreakPointInfo> info,
Handle<Object> break_point_object);
Handle<BreakPoint> break_point);
// Set a break point.
static void SetBreakPoint(Handle<BreakPointInfo> info,
Handle<Object> break_point_object);
// Check if break point info has this break point object.
static bool HasBreakPointObject(Handle<BreakPointInfo> info,
Handle<Object> break_point_object);
Handle<BreakPoint> break_point);
// Check if break point info has this break point.
static bool HasBreakPoint(Handle<BreakPointInfo> info,
Handle<BreakPoint> break_point);
// Get the number of break points for this code offset.
int GetBreakPointCount();
......@@ -153,7 +154,7 @@ class BreakPointInfo : public Tuple2 {
DECL_CAST(BreakPointInfo)
static const int kSourcePositionOffset = kValue1Offset;
static const int kBreakPointObjectsOffset = kValue2Offset;
static const int kBreakPointsOffset = kValue2Offset;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BreakPointInfo);
......
......@@ -85,27 +85,6 @@ RUNTIME_FUNCTION(Runtime_HandleDebuggerStatement) {
}
// Adds a JavaScript function as a debug event listener.
// args[0]: debug event listener function to set or null or undefined for
// clearing the event listener function
// args[1]: object supplied during callback
RUNTIME_FUNCTION(Runtime_SetDebugEventListener) {
SealHandleScope shs(isolate);
DCHECK_EQ(2, args.length());
CHECK(args[0]->IsJSFunction() || args[0]->IsNullOrUndefined(isolate));
CONVERT_ARG_HANDLE_CHECKED(Object, callback, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, data, 1);
if (callback->IsJSFunction()) {
JavaScriptDebugDelegate* delegate = new JavaScriptDebugDelegate(
isolate, Handle<JSFunction>::cast(callback), data);
isolate->debug()->SetDebugDelegate(delegate, true);
} else {
isolate->debug()->SetDebugDelegate(nullptr, false);
}
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_ScheduleBreak) {
SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length());
......@@ -1041,16 +1020,6 @@ RUNTIME_FUNCTION(Runtime_SetScopeVariableValue) {
return isolate->heap()->ToBoolean(res);
}
// Sets the disable break state
// args[0]: disable break state
RUNTIME_FUNCTION(Runtime_SetBreakPointsActive) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_BOOLEAN_ARG_CHECKED(active, 0);
isolate->debug()->set_break_points_active(active);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
HandleScope scope(isolate);
......@@ -1070,71 +1039,6 @@ RUNTIME_FUNCTION(Runtime_GetBreakLocations) {
}
// Set a break point in a function.
// args[0]: function
// args[1]: number: break source position (within the function source)
// args[2]: number: break point object
RUNTIME_FUNCTION(Runtime_SetFunctionBreakPoint) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CHECK(isolate->debug()->is_active());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
CHECK(source_position >= function->shared()->start_position() &&
source_position <= function->shared()->end_position());
CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
// Set break point.
CHECK(isolate->debug()->SetBreakPoint(function, break_point_object_arg,
&source_position));
return Smi::FromInt(source_position);
}
// Changes the state of a break point in a script and returns source position
// where break point was set. NOTE: Regarding performance see the NOTE for
// GetScriptFromScriptData.
// args[0]: script to set break point in
// args[1]: number: break source position (within the script source)
// args[2]: number: break point object
RUNTIME_FUNCTION(Runtime_SetScriptBreakPoint) {
HandleScope scope(isolate);
DCHECK_EQ(3, args.length());
CHECK(isolate->debug()->is_active());
CONVERT_ARG_HANDLE_CHECKED(JSValue, wrapper, 0);
CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
CHECK_GE(source_position, 0);
CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 2);
// Get the script from the script wrapper.
CHECK(wrapper->value()->IsScript());
Handle<Script> script(Script::cast(wrapper->value()));
// Set break point.
if (!isolate->debug()->SetBreakPointForScript(script, break_point_object_arg,
&source_position)) {
return isolate->heap()->undefined_value();
}
return Smi::FromInt(source_position);
}
// Clear a break point
// args[0]: number: break point object
RUNTIME_FUNCTION(Runtime_ClearBreakPoint) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CHECK(isolate->debug()->is_active());
CONVERT_ARG_HANDLE_CHECKED(Object, break_point_object_arg, 0);
// Clear break point.
isolate->debug()->ClearBreakPoint(break_point_object_arg);
return isolate->heap()->undefined_value();
}
// Change the state of break on exceptions.
// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
// args[1]: Boolean indicating on/off.
......@@ -1720,44 +1624,6 @@ RUNTIME_FUNCTION(Runtime_ScriptPositionInfo2) {
return *GetJSPositionInfo(script, position, offset_flag, isolate);
}
// Returns the given line as a string, or null if line is out of bounds.
// The parameter line is expected to include the script's line offset.
// TODO(5530): Remove once uses in debug.js are gone.
RUNTIME_FUNCTION(Runtime_ScriptSourceLine) {
HandleScope scope(isolate);
DCHECK_EQ(2, args.length());
CONVERT_ARG_CHECKED(JSValue, script, 0);
CONVERT_NUMBER_CHECKED(int32_t, line, Int32, args[1]);
CHECK(script->value()->IsScript());
Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
if (script_handle->type() == Script::TYPE_WASM) {
// Return null for now; this function will disappear soon anyway.
return isolate->heap()->null_value();
}
Script::InitLineEnds(script_handle);
FixedArray* line_ends_array = FixedArray::cast(script_handle->line_ends());
const int line_count = line_ends_array->length();
line -= script_handle->line_offset();
if (line < 0 || line_count <= line) {
return isolate->heap()->null_value();
}
const int start =
(line == 0) ? 0 : Smi::ToInt(line_ends_array->get(line - 1)) + 1;
const int end = Smi::ToInt(line_ends_array->get(line));
Handle<String> source =
handle(String::cast(script_handle->source()), isolate);
Handle<String> str = isolate->factory()->NewSubString(source, start, end);
return *str;
}
// On function call, depending on circumstances, prepare for stepping in,
// or perform a side effect check.
RUNTIME_FUNCTION(Runtime_DebugOnFunctionCall) {
......
......@@ -128,7 +128,6 @@ namespace internal {
#define FOR_EACH_INTRINSIC_DEBUG(F) \
F(HandleDebuggerStatement, 0, 1) \
F(SetDebugEventListener, 2, 1) \
F(ScheduleBreak, 0, 1) \
F(DebugGetInternalProperties, 1, 1) \
F(DebugGetPropertyDetails, 2, 1) \
......@@ -146,11 +145,7 @@ namespace internal {
F(GetGeneratorScopeCount, 1, 1) \
F(GetGeneratorScopeDetails, 2, 1) \
F(SetScopeVariableValue, 6, 1) \
F(SetBreakPointsActive, 1, 1) \
F(GetBreakLocations, 1, 1) \
F(SetFunctionBreakPoint, 3, 1) \
F(SetScriptBreakPoint, 3, 1) \
F(ClearBreakPoint, 1, 1) \
F(ChangeBreakOnException, 2, 1) \
F(IsBreakOnException, 1, 1) \
F(PrepareStep, 2, 1) \
......@@ -173,7 +168,6 @@ namespace internal {
F(ScriptLocationFromLine2, 4, 1) \
F(ScriptPositionInfo, 3, 1) \
F(ScriptPositionInfo2, 3, 1) \
F(ScriptSourceLine, 2, 1) \
F(DebugOnFunctionCall, 1, 1) \
F(DebugPrepareStepInSuspendedGenerator, 0, 1) \
F(DebugPushPromise, 1, 1) \
......
......@@ -1049,7 +1049,7 @@ int FindBreakpointInfoInsertPos(Isolate* isolate,
void WasmSharedModuleData::AddBreakpoint(Handle<WasmSharedModuleData> shared,
int position,
Handle<Object> break_point_object) {
Handle<BreakPoint> break_point) {
Isolate* isolate = shared->GetIsolate();
Handle<FixedArray> breakpoint_infos;
if (shared->has_breakpoint_infos()) {
......@@ -1069,7 +1069,7 @@ void WasmSharedModuleData::AddBreakpoint(Handle<WasmSharedModuleData> shared,
position) {
Handle<BreakPointInfo> old_info(
BreakPointInfo::cast(breakpoint_infos->get(insert_pos)), isolate);
BreakPointInfo::SetBreakPoint(old_info, break_point_object);
BreakPointInfo::SetBreakPoint(old_info, break_point);
return;
}
......@@ -1096,7 +1096,7 @@ void WasmSharedModuleData::AddBreakpoint(Handle<WasmSharedModuleData> shared,
// Generate new BreakpointInfo.
Handle<BreakPointInfo> breakpoint_info =
isolate->factory()->NewBreakPointInfo(position);
BreakPointInfo::SetBreakPoint(breakpoint_info, break_point_object);
BreakPointInfo::SetBreakPoint(breakpoint_info, break_point);
// Now insert new position at insert_pos.
new_breakpoint_infos->set(insert_pos, *breakpoint_info);
......@@ -1368,9 +1368,8 @@ MaybeHandle<FixedArray> WasmSharedModuleData::CheckBreakPoints(
Handle<BreakPointInfo>::cast(maybe_breakpoint_info);
if (breakpoint_info->source_position() != position) return {};
Handle<Object> breakpoint_objects(breakpoint_info->break_point_objects(),
isolate);
return isolate->debug()->GetHitBreakPointObjects(breakpoint_objects);
Handle<Object> break_points(breakpoint_info->break_points(), isolate);
return isolate->debug()->GetHitBreakPoints(break_points);
}
Handle<WasmCompiledModule> WasmCompiledModule::New(
......@@ -1809,10 +1808,9 @@ bool WasmSharedModuleData::GetPositionInfo(uint32_t position,
return true;
}
bool WasmCompiledModule::SetBreakPoint(
Handle<WasmCompiledModule> compiled_module, int* position,
Handle<Object> break_point_object) {
Handle<BreakPoint> break_point) {
Isolate* isolate = compiled_module->GetIsolate();
Handle<WasmSharedModuleData> shared(compiled_module->shared(), isolate);
......@@ -1827,7 +1825,7 @@ bool WasmCompiledModule::SetBreakPoint(
DCHECK(IsBreakablePosition(*shared, func_index, offset_in_func));
// Insert new break point into break_positions of shared module data.
WasmSharedModuleData::AddBreakpoint(shared, *position, break_point_object);
WasmSharedModuleData::AddBreakpoint(shared, *position, break_point);
// Iterate over all instances of this module and tell them to set this new
// breakpoint.
......
......@@ -337,7 +337,7 @@ class WasmSharedModuleData : public FixedArray {
Handle<WasmSharedModuleData>);
static void AddBreakpoint(Handle<WasmSharedModuleData>, int position,
Handle<Object> break_point_object);
Handle<BreakPoint> break_point);
static void SetBreakpointsOnNewInstance(Handle<WasmSharedModuleData>,
Handle<WasmInstanceObject>);
......@@ -569,7 +569,7 @@ class WasmCompiledModule : public FixedArray {
// If it points outside a function, or behind the last breakable location,
// this function returns false and does not set any breakpoint.
static bool SetBreakPoint(Handle<WasmCompiledModule>, int* position,
Handle<Object> break_point_object);
Handle<BreakPoint> break_point);
inline void ReplaceCodeTableForTesting(
std::vector<wasm::WasmCode*>&& testing_table);
......
......@@ -2971,7 +2971,6 @@ class CountBreakDebugDelegate : public v8::debug::DebugDelegate {
public:
void BreakProgramRequested(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object> exec_state,
v8::Local<v8::Value> break_points_hit,
const std::vector<int>&) override {
debug_break_count++;
}
......
......@@ -166,115 +166,27 @@ static bool HasBreakInfo(v8::Local<v8::Function> fun) {
return shared->HasBreakInfo();
}
// Set a break point in a function with a position relative to function start,
// and return the associated break point number.
static int SetBreakPoint(v8::Local<v8::Function> fun, int position) {
i::Handle<i::JSFunction> function =
i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
position += function->shared()->start_position();
static int break_point = 0;
v8::internal::Isolate* isolate = function->GetIsolate();
v8::internal::Debug* debug = isolate->debug();
debug->SetBreakPoint(
function,
Handle<Object>(v8::internal::Smi::FromInt(++break_point), isolate),
&position);
return break_point;
}
// Set a break point in a function with a position relative to function start,
// and return the associated break point number.
static i::Handle<i::BreakPoint> SetBreakPoint(v8::Local<v8::Function> fun,
int position,
const char* condition) {
const char* condition = nullptr) {
i::Handle<i::JSFunction> function =
i::Handle<i::JSFunction>::cast(v8::Utils::OpenHandle(*fun));
position += function->shared()->start_position();
static int break_point_index = 0;
i::Isolate* isolate = function->GetIsolate();
i::Handle<i::String> condition_string =
condition ? isolate->factory()->NewStringFromAsciiChecked(condition)
: isolate->factory()->empty_string();
i::Debug* debug = isolate->debug();
i::Handle<i::BreakPoint> break_point = isolate->factory()->NewBreakPoint(
++break_point_index,
isolate->factory()->NewStringFromAsciiChecked(condition));
i::Handle<i::BreakPoint> break_point =
isolate->factory()->NewBreakPoint(++break_point_index, condition_string);
debug->SetBreakPoint(function, break_point, &position);
return break_point;
}
// Set a break point in a function using the Debug object and return the
// associated break point number.
static int SetBreakPointFromJS(v8::Isolate* isolate,
const char* function_name,
int line, int position) {
EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
SNPrintF(buffer,
"debug.Debug.setBreakPoint(%s,%d,%d)",
function_name, line, position);
buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
return value->Int32Value(isolate->GetCurrentContext()).FromJust();
}
// Set a break point in a script identified by id using the global Debug object.
static int SetScriptBreakPointByIdFromJS(v8::Isolate* isolate, int script_id,
int line, int column) {
EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
if (column >= 0) {
// Column specified set script break point on precise location.
SNPrintF(buffer,
"debug.Debug.setScriptBreakPointById(%d,%d,%d)",
script_id, line, column);
} else {
// Column not specified set script break point on line.
SNPrintF(buffer,
"debug.Debug.setScriptBreakPointById(%d,%d)",
script_id, line);
}
buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
{
v8::TryCatch try_catch(isolate);
v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
CHECK(!try_catch.HasCaught());
return value->Int32Value(isolate->GetCurrentContext()).FromJust();
}
}
// Set a break point in a script identified by name using the global Debug
// object.
static int SetScriptBreakPointByNameFromJS(v8::Isolate* isolate,
const char* script_name, int line,
int column) {
EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
if (column >= 0) {
// Column specified set script break point on precise location.
SNPrintF(buffer,
"debug.Debug.setScriptBreakPointByName(\"%s\",%d,%d)",
script_name, line, column);
} else {
// Column not specified set script break point on line.
SNPrintF(buffer,
"debug.Debug.setScriptBreakPointByName(\"%s\",%d)",
script_name, line);
}
buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
{
v8::TryCatch try_catch(isolate);
v8::Local<v8::Value> value = CompileRunChecked(isolate, buffer.start());
CHECK(!try_catch.HasCaught());
return value->Int32Value(isolate->GetCurrentContext()).FromJust();
}
}
// Clear a break point.
static void ClearBreakPoint(int break_point) {
v8::internal::Isolate* isolate = CcTest::i_isolate();
v8::internal::Debug* debug = isolate->debug();
debug->ClearBreakPoint(
Handle<Object>(v8::internal::Smi::FromInt(break_point), isolate));
}
static void ClearBreakPoint(i::Handle<i::BreakPoint> break_point) {
v8::internal::Isolate* isolate = CcTest::i_isolate();
......@@ -282,51 +194,6 @@ static void ClearBreakPoint(i::Handle<i::BreakPoint> break_point) {
debug->ClearBreakPoint(break_point);
}
// Clear a break point using the global Debug object.
static void ClearBreakPointFromJS(v8::Isolate* isolate,
int break_point_number) {
EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
SNPrintF(buffer,
"debug.Debug.clearBreakPoint(%d)",
break_point_number);
buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
CompileRunChecked(isolate, buffer.start());
}
static void EnableScriptBreakPointFromJS(v8::Isolate* isolate,
int break_point_number) {
EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
SNPrintF(buffer,
"debug.Debug.enableScriptBreakPoint(%d)",
break_point_number);
buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
CompileRunChecked(isolate, buffer.start());
}
static void DisableScriptBreakPointFromJS(v8::Isolate* isolate,
int break_point_number) {
EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
SNPrintF(buffer,
"debug.Debug.disableScriptBreakPoint(%d)",
break_point_number);
buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
CompileRunChecked(isolate, buffer.start());
}
static void ChangeScriptBreakPointConditionFromJS(v8::Isolate* isolate,
int break_point_number,
const char* condition) {
EmbeddedVector<char, SMALL_STRING_BUFFER_SIZE> buffer;
SNPrintF(buffer,
"debug.Debug.changeScriptBreakPointCondition(%d, \"%s\")",
break_point_number, condition);
buffer[SMALL_STRING_BUFFER_SIZE - 1] = '\0';
CompileRunChecked(isolate, buffer.start());
}
// Change break on exception.
static void ChangeBreakOnException(bool caught, bool uncaught) {
......@@ -608,8 +475,6 @@ static void DebugEventBreakPointHitCount(
int exception_hit_count = 0;
int uncaught_exception_hit_count = 0;
int last_js_stack_height = -1;
v8::Local<v8::Function> debug_event_listener_callback;
int debug_event_listener_callback_result;
static void DebugEventCounterClear() {
break_point_hit_count = 0;
......@@ -656,16 +521,6 @@ static void DebugEventCounter(
frame_count->Call(context, exec_state, kArgc, argv).ToLocalChecked();
last_js_stack_height = result->Int32Value(context).FromJust();
}
// Run callback from DebugEventListener and check the result.
if (!debug_event_listener_callback.IsEmpty()) {
v8::Local<v8::Value> result =
debug_event_listener_callback->Call(context, event_data, 0, nullptr)
.ToLocalChecked();
CHECK(!result.IsEmpty());
CHECK_EQ(debug_event_listener_callback_result,
result->Int32Value(context).FromJust());
}
}
......@@ -724,7 +579,7 @@ static void DebugEventEvaluate(
// This debug event listener removes a breakpoint in a function
int debug_event_remove_break_point = 0;
i::Handle<i::BreakPoint> debug_event_remove_break_point;
static void DebugEventRemoveBreakPoint(
const v8::Debug::EventDetails& event_details) {
v8::DebugEvent event = event_details.GetEvent();
......@@ -919,12 +774,12 @@ TEST(DebugInfo) {
CHECK(!HasBreakInfo(bar));
EnableDebugger(env->GetIsolate());
// One function (foo) is debugged.
int bp1 = SetBreakPoint(foo, 0);
i::Handle<i::BreakPoint> bp1 = SetBreakPoint(foo, 0);
CHECK_EQ(1, v8::internal::GetDebuggedFunctions()->length());
CHECK(HasBreakInfo(foo));
CHECK(!HasBreakInfo(bar));
// Two functions are debugged.
int bp2 = SetBreakPoint(bar, 0);
i::Handle<i::BreakPoint> bp2 = SetBreakPoint(bar, 0);
CHECK_EQ(2, v8::internal::GetDebuggedFunctions()->length());
CHECK(HasBreakInfo(foo));
CHECK(HasBreakInfo(bar));
......@@ -957,7 +812,7 @@ TEST(BreakPointICStore) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint
int bp = SetBreakPoint(foo, 0);
i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
......@@ -1020,7 +875,7 @@ TEST(BreakPointICLoad) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
int bp = SetBreakPoint(foo, 0);
i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
......@@ -1051,7 +906,7 @@ TEST(BreakPointICCall) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint
int bp = SetBreakPoint(foo, 0);
i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
foo->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
......@@ -1086,7 +941,7 @@ TEST(BreakPointICCallWithGC) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
int bp = SetBreakPoint(foo, 0);
i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
.ToLocalChecked()
->Int32Value(context)
......@@ -1127,7 +982,7 @@ TEST(BreakPointConstructCallWithGC) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
int bp = SetBreakPoint(foo, 0);
i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
CHECK_EQ(1, foo->Call(context, env->Global(), 0, nullptr)
.ToLocalChecked()
->Int32Value(context)
......@@ -1174,7 +1029,7 @@ TEST(BreakPointReturn) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint
int bp = SetBreakPoint(foo, 0);
i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
CHECK_EQ(0, last_source_line);
......@@ -1211,7 +1066,7 @@ TEST(BreakPointBuiltin) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
int bp = SetBreakPoint(builtin, 0);
i::Handle<i::BreakPoint> bp = SetBreakPoint(builtin, 0);
CompileRun("'b'.repeat(10)");
CHECK_EQ(1, break_point_hit_count);
......@@ -1405,7 +1260,7 @@ TEST(BreakPointInlining) {
CHECK_EQ(0, break_point_hit_count);
// Run with breakpoint.
int bp = SetBreakPoint(inlinee, 0);
i::Handle<i::BreakPoint> bp = SetBreakPoint(inlinee, 0);
CompileRun("f(0.1);");
CHECK_EQ(1, break_point_hit_count);
CompileRun("test(0.2);");
......@@ -1558,716 +1413,6 @@ TEST(BreakPointSurviveGC) {
}
// Test that break points can be set using the global Debug object.
TEST(BreakPointThroughJavaScript) {
break_point_hit_count = 0;
DebugLocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = env.context();
env.ExposeDebug();
SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
CompileRunChecked(isolate, "function bar(){}");
CompileFunction(isolate, "function foo(){bar();bar();}", "foo");
// 012345678901234567890
// 1 2
// Break points are set at position 3 and 9
v8::Local<v8::String> source = v8_str(env->GetIsolate(), "foo()");
v8::Local<v8::Script> foo =
v8::Script::Compile(context, source).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
// Run with one breakpoint
int bp1 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 3);
foo->Run(context).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
foo->Run(context).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
// Run with two breakpoints
int bp2 = SetBreakPointFromJS(env->GetIsolate(), "foo", 0, 9);
foo->Run(context).ToLocalChecked();
CHECK_EQ(4, break_point_hit_count);
foo->Run(context).ToLocalChecked();
CHECK_EQ(6, break_point_hit_count);
// Run with one breakpoint
ClearBreakPointFromJS(env->GetIsolate(), bp2);
foo->Run(context).ToLocalChecked();
CHECK_EQ(7, break_point_hit_count);
foo->Run(context).ToLocalChecked();
CHECK_EQ(8, break_point_hit_count);
// Run without breakpoints.
ClearBreakPointFromJS(env->GetIsolate(), bp1);
foo->Run(context).ToLocalChecked();
CHECK_EQ(8, break_point_hit_count);
SetDebugEventListener(isolate, nullptr);
CheckDebuggerUnloaded();
// Make sure that the break point numbers are consecutive.
CHECK_EQ(1, bp1);
CHECK_EQ(2, bp2);
}
// Test that break points on scripts identified by name can be set using the
// global Debug object.
TEST(ScriptBreakPointByNameThroughJavaScript) {
break_point_hit_count = 0;
DebugLocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = env.context();
env.ExposeDebug();
SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
v8::Local<v8::String> script = v8_str(isolate,
"function f() {\n"
" function h() {\n"
" a = 0; // line 2\n"
" }\n"
" b = 1; // line 4\n"
" return h();\n"
"}\n"
"\n"
"function g() {\n"
" function h() {\n"
" a = 0;\n"
" }\n"
" b = 2; // line 12\n"
" h();\n"
" b = 3; // line 14\n"
" f(); // line 15\n"
"}");
// Compile the script and get the two functions.
v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
v8::Script::Compile(context, script, &origin)
.ToLocalChecked()
->Run(context)
.ToLocalChecked();
v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
env->Global()->Get(context, v8_str(isolate, "g")).ToLocalChecked());
// Call f and g without break points.
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
// Call f and g with break point on line 12.
int sbp1 = SetScriptBreakPointByNameFromJS(isolate, "test", 12, 0);
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
// Remove the break point again.
break_point_hit_count = 0;
ClearBreakPointFromJS(env->GetIsolate(), sbp1);
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
// Call f and g with break point on line 2.
int sbp2 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 2, 0);
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
// Call f and g with break point on line 2, 4, 12, 14 and 15.
int sbp3 = SetScriptBreakPointByNameFromJS(isolate, "test", 4, 0);
int sbp4 = SetScriptBreakPointByNameFromJS(isolate, "test", 12, 0);
int sbp5 = SetScriptBreakPointByNameFromJS(isolate, "test", 14, 0);
int sbp6 = SetScriptBreakPointByNameFromJS(isolate, "test", 15, 0);
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(7, break_point_hit_count);
// Remove all the break points again.
break_point_hit_count = 0;
ClearBreakPointFromJS(isolate, sbp2);
ClearBreakPointFromJS(isolate, sbp3);
ClearBreakPointFromJS(isolate, sbp4);
ClearBreakPointFromJS(isolate, sbp5);
ClearBreakPointFromJS(isolate, sbp6);
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
SetDebugEventListener(isolate, nullptr);
CheckDebuggerUnloaded();
// Make sure that the break point numbers are consecutive.
CHECK_EQ(1, sbp1);
CHECK_EQ(2, sbp2);
CHECK_EQ(3, sbp3);
CHECK_EQ(4, sbp4);
CHECK_EQ(5, sbp5);
CHECK_EQ(6, sbp6);
}
TEST(ScriptBreakPointByIdThroughJavaScript) {
break_point_hit_count = 0;
DebugLocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = env.context();
env.ExposeDebug();
SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
v8::Local<v8::String> source = v8_str(isolate,
"function f() {\n"
" function h() {\n"
" a = 0; // line 2\n"
" }\n"
" b = 1; // line 4\n"
" return h();\n"
"}\n"
"\n"
"function g() {\n"
" function h() {\n"
" a = 0;\n"
" }\n"
" b = 2; // line 12\n"
" h();\n"
" b = 3; // line 14\n"
" f(); // line 15\n"
"}");
// Compile the script and get the two functions.
v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
v8::Local<v8::Script> script =
v8::Script::Compile(context, source, &origin).ToLocalChecked();
script->Run(context).ToLocalChecked();
v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast(
env->Global()->Get(context, v8_str(isolate, "g")).ToLocalChecked());
// Get the script id knowing that internally it is a 32 integer.
int script_id = script->GetUnboundScript()->GetId();
// Call f and g without break points.
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
// Call f and g with break point on line 12.
int sbp1 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
// Remove the break point again.
break_point_hit_count = 0;
ClearBreakPointFromJS(env->GetIsolate(), sbp1);
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
// Call f and g with break point on line 2.
int sbp2 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 2, 0);
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
// Call f and g with break point on line 2, 4, 12, 14 and 15.
int sbp3 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 4, 0);
int sbp4 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 12, 0);
int sbp5 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 14, 0);
int sbp6 = SetScriptBreakPointByIdFromJS(env->GetIsolate(), script_id, 15, 0);
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(7, break_point_hit_count);
// Remove all the break points again.
break_point_hit_count = 0;
ClearBreakPointFromJS(env->GetIsolate(), sbp2);
ClearBreakPointFromJS(env->GetIsolate(), sbp3);
ClearBreakPointFromJS(env->GetIsolate(), sbp4);
ClearBreakPointFromJS(env->GetIsolate(), sbp5);
ClearBreakPointFromJS(env->GetIsolate(), sbp6);
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
SetDebugEventListener(isolate, nullptr);
CheckDebuggerUnloaded();
// Make sure that the break point numbers are consecutive.
CHECK_EQ(1, sbp1);
CHECK_EQ(2, sbp2);
CHECK_EQ(3, sbp3);
CHECK_EQ(4, sbp4);
CHECK_EQ(5, sbp5);
CHECK_EQ(6, sbp6);
}
// Test conditional script break points.
TEST(EnableDisableScriptBreakPoint) {
break_point_hit_count = 0;
DebugLocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
v8::Local<v8::Context> context = env.context();
env.ExposeDebug();
SetDebugEventListener(isolate, DebugEventBreakPointHitCount);
v8::Local<v8::String> script = v8_str(isolate,
"function f() {\n"
" a = 0; // line 1\n"
"};");
// Compile the script and get function f.
v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(isolate, "test"));
v8::Script::Compile(context, script, &origin)
.ToLocalChecked()
->Run(context)
.ToLocalChecked();
v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
env->Global()->Get(context, v8_str(isolate, "f")).ToLocalChecked());
// Set script break point on line 1 (in function f).
int sbp = SetScriptBreakPointByNameFromJS(isolate, "test", 1, 0);
// Call f while enabeling and disabling the script break point.
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
DisableScriptBreakPointFromJS(isolate, sbp);
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
EnableScriptBreakPointFromJS(isolate, sbp);
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
DisableScriptBreakPointFromJS(isolate, sbp);
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
SetDebugEventListener(isolate, nullptr);
CheckDebuggerUnloaded();
}
// Test conditional script break points.
TEST(ConditionalScriptBreakPoint) {
break_point_hit_count = 0;
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
env.ExposeDebug();
SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
v8::Local<v8::String> script = v8_str(env->GetIsolate(),
"count = 0;\n"
"function f() {\n"
" g(count++); // line 2\n"
"};\n"
"function g(x) {\n"
" var a=x; // line 5\n"
"};");
// Compile the script and get function f.
v8::Local<v8::Context> context = env.context();
v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test"));
v8::Script::Compile(context, script, &origin)
.ToLocalChecked()
->Run(context)
.ToLocalChecked();
v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(
env->Global()
->Get(context, v8_str(env->GetIsolate(), "f"))
.ToLocalChecked());
// Set script break point on line 5 (in function g).
int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 5, 0);
// Call f with different conditions on the script break point.
break_point_hit_count = 0;
ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "false");
f->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "true");
break_point_hit_count = 0;
f->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
ChangeScriptBreakPointConditionFromJS(env->GetIsolate(), sbp1, "x % 2 == 0");
break_point_hit_count = 0;
for (int i = 0; i < 10; i++) {
f->Call(env.context(), env->Global(), 0, nullptr).ToLocalChecked();
}
CHECK_EQ(5, break_point_hit_count);
SetDebugEventListener(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded();
}
// Test when several scripts has the same script data
TEST(ScriptBreakPointMultiple) {
break_point_hit_count = 0;
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
env.ExposeDebug();
SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
v8::Local<v8::Context> context = env.context();
v8::Local<v8::Function> f;
v8::Local<v8::String> script_f = v8_str(env->GetIsolate(),
"function f() {\n"
" a = 0; // line 1\n"
"}");
v8::Local<v8::Function> g;
v8::Local<v8::String> script_g = v8_str(env->GetIsolate(),
"function g() {\n"
" b = 0; // line 1\n"
"}");
v8::ScriptOrigin origin = v8::ScriptOrigin(v8_str(env->GetIsolate(), "test"));
// Compile the scripts with same script data and get the functions.
v8::Script::Compile(context, script_f, &origin)
.ToLocalChecked()
->Run(context)
.ToLocalChecked();
f = v8::Local<v8::Function>::Cast(
env->Global()
->Get(context, v8_str(env->GetIsolate(), "f"))
.ToLocalChecked());
v8::Script::Compile(context, script_g, &origin)
.ToLocalChecked()
->Run(context)
.ToLocalChecked();
g = v8::Local<v8::Function>::Cast(
env->Global()
->Get(context, v8_str(env->GetIsolate(), "g"))
.ToLocalChecked());
int sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
// Call f and g and check that the script break point is active.
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
// Clear the script break point.
ClearBreakPointFromJS(env->GetIsolate(), sbp);
// Call f and g and check that the script break point is no longer active.
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
// Set script break point with the scripts loaded.
sbp = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test", 1, 0);
// Call f and g and check that the script break point is active.
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
SetDebugEventListener(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded();
}
// Test the script origin which has both name and line offset.
TEST(ScriptBreakPointLineOffset) {
break_point_hit_count = 0;
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
env.ExposeDebug();
SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
v8::Local<v8::Context> context = env.context();
v8::Local<v8::Function> f;
v8::Local<v8::String> script =
v8_str(env->GetIsolate(),
"function f() {\n"
" a = 0; // line 8 as this script has line offset 7\n"
" b = 0; // line 9 as this script has line offset 7\n"
"}");
// Create script origin both name and line offset.
v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"),
v8::Integer::New(env->GetIsolate(), 7));
// Compile the script and get the function.
v8::Script::Compile(context, script, &origin)
.ToLocalChecked()
->Run(context)
.ToLocalChecked();
int sbp1 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 8, 0);
int sbp2 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
f = v8::Local<v8::Function>::Cast(
env->Global()
->Get(context, v8_str(env->GetIsolate(), "f"))
.ToLocalChecked());
// Call f and check that the script break point is active.
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
// Clear the script break points.
ClearBreakPointFromJS(env->GetIsolate(), sbp1);
ClearBreakPointFromJS(env->GetIsolate(), sbp2);
// Call f and check that no script break points are active.
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
// Set a script break point with the script loaded.
sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 9, 0);
// Call f and check that the script break point is active.
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
SetDebugEventListener(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded();
}
// Test script break points set on lines.
TEST(ScriptBreakPointLine) {
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
env.ExposeDebug();
// Create a function for checking the function when hitting a break point.
frame_function_name = CompileFunction(&env,
frame_function_name_source,
"frame_function_name");
SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
v8::Local<v8::Context> context = env.context();
v8::Local<v8::Function> f;
v8::Local<v8::Function> g;
v8::Local<v8::String> script =
v8_str(env->GetIsolate(),
"a = 0 // line 0\n"
"function f() {\n"
" a = 1; // line 2\n"
"}\n"
" a = 2; // line 4\n"
" /* xx */ function g() { // line 5\n"
" function h() { // line 6\n"
" a = 3; // line 7\n"
" }\n"
" h(); // line 9\n"
" a = 4; // line 10\n"
" }\n"
" a=5; // line 12");
// Compile the script and get the function.
break_point_hit_count = 0;
v8::ScriptOrigin origin(v8_str(env->GetIsolate(), "test.html"),
v8::Integer::New(env->GetIsolate(), 0));
v8::Local<v8::Script> compiled =
v8::Script::Compile(context, script, &origin).ToLocalChecked();
int sbp1 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 0, -1);
int sbp2 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 1, -1);
int sbp3 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 5, -1);
compiled->Run(context).ToLocalChecked();
f = v8::Local<v8::Function>::Cast(
env->Global()
->Get(context, v8_str(env->GetIsolate(), "f"))
.ToLocalChecked());
g = v8::Local<v8::Function>::Cast(
env->Global()
->Get(context, v8_str(env->GetIsolate(), "g"))
.ToLocalChecked());
// Check that a break point was hit when the script was run.
CHECK_EQ(1, break_point_hit_count);
CHECK_EQ(0, StrLength(last_function_hit));
// Call f and check that the script break point.
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(2, break_point_hit_count);
CHECK_EQ(0, strcmp("f", last_function_hit));
// Call g and check that the script break point.
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(3, break_point_hit_count);
CHECK_EQ(0, strcmp("g", last_function_hit));
// Clear the script break point on g and set one on h.
ClearBreakPointFromJS(env->GetIsolate(), sbp3);
int sbp4 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 6, -1);
// Call g and check that the script break point in h is hit.
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(4, break_point_hit_count);
CHECK_EQ(0, strcmp("h", last_function_hit));
// Clear break points in f and h. Set a new one in the script between
// functions f and g and test that there is no break points in f and g any
// more.
ClearBreakPointFromJS(env->GetIsolate(), sbp2);
ClearBreakPointFromJS(env->GetIsolate(), sbp4);
int sbp5 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 4, -1);
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
g->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
// Set a break point in the code after the last function decleration.
int sbp6 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 12, -1);
// Reloading the script should not hit any break points.
break_point_hit_count = 0;
v8::Script::Compile(context, script, &origin)
.ToLocalChecked()
->Run(context)
.ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
ClearBreakPointFromJS(env->GetIsolate(), sbp1);
ClearBreakPointFromJS(env->GetIsolate(), sbp5);
ClearBreakPointFromJS(env->GetIsolate(), sbp6);
SetDebugEventListener(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded();
}
// Test top level script break points set on lines.
TEST(ScriptBreakPointLineTopLevel) {
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
env.ExposeDebug();
SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
v8::Local<v8::Context> context = env.context();
v8::Local<v8::String> script =
v8_str(env->GetIsolate(),
"function f() {\n"
" a = 1; // line 1\n"
"}\n"
"a = 2; // line 3\n");
v8::Local<v8::Function> f;
{
v8::HandleScope scope(env->GetIsolate());
CompileRunWithOrigin(script, "test.html");
}
f = v8::Local<v8::Function>::Cast(
env->Global()
->Get(context, v8_str(env->GetIsolate(), "f"))
.ToLocalChecked());
CcTest::CollectAllGarbage();
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
// Call f and check that there was no break points.
break_point_hit_count = 0;
f->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(0, break_point_hit_count);
// Recompile and run script and check that break point was not reapplied.
break_point_hit_count = 0;
CompileRunWithOrigin(script, "test.html");
CHECK_EQ(0, break_point_hit_count);
SetDebugEventListener(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded();
}
// Test that it is possible to add and remove break points in a top level
// function which has no references but has not been collected yet.
TEST(ScriptBreakPointTopLevelCrash) {
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
env.ExposeDebug();
SetDebugEventListener(env->GetIsolate(), DebugEventBreakPointHitCount);
CompileRunWithOrigin(
"function f() {\n"
" return 0;\n"
"}\n",
"test.html");
int sbp1 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 1, -1);
break_point_hit_count = 0;
CompileRun("f();");
CHECK_EQ(1, break_point_hit_count);
int sbp2 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), "test.html", 3, -1);
ClearBreakPointFromJS(env->GetIsolate(), sbp1);
ClearBreakPointFromJS(env->GetIsolate(), sbp2);
SetDebugEventListener(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded();
}
// Test that it is possible to remove the last break point for a function
// inside the break handling of that break point.
......@@ -2357,7 +1502,7 @@ TEST(DebuggerStatementBreakpoint) {
foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
CHECK_EQ(1, break_point_hit_count);
int bp = SetBreakPoint(foo, 0);
i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, 0);
// Set breakpoint does not duplicate hits
foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
......@@ -2419,7 +1564,7 @@ TEST(DebugEvaluate) {
v8_str(env->GetIsolate(), "Hello, world!")};
// Call foo with breakpoint set before a=x and undefined as parameter.
int bp = SetBreakPoint(foo, foo_break_position_1);
i::Handle<i::BreakPoint> bp = SetBreakPoint(foo, foo_break_position_1);
checks = checks_uu;
foo->Call(context, env->Global(), 0, nullptr).ToLocalChecked();
......@@ -2474,7 +1619,6 @@ TEST(DebugEvaluate) {
" y=0; /* To ensure break location.*/"
" a=x;"
" };"
" debug.Debug.clearAllBreakPoints();"
" barbar();"
" y=0;a=x;"
"}",
......@@ -2533,7 +1677,7 @@ TEST(ConditionalBreakpointWithCodeGenerationDisallowed) {
"foo");
// Set conditional breakpoint with condition 'true'.
CompileRun("debug.Debug.setBreakPoint(foo, 2, 0, 'true')");
SetBreakPoint(foo, 4, "true");
debugEventCount = 0;
env->AllowCodeGenerationFromStrings(false);
......@@ -3689,6 +2833,7 @@ TEST(DebugStepFunctionCallApply) {
TEST(PauseInScript) {
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(env->GetIsolate());
env.ExposeDebug();
// Register a debug event listener which counts.
......@@ -3706,7 +2851,12 @@ TEST(PauseInScript) {
.ToLocalChecked();
// Set breakpoint in the script.
SetScriptBreakPointByNameFromJS(env->GetIsolate(), script_name, 0, -1);
i::Handle<i::BreakPoint> break_point =
isolate->factory()->NewBreakPoint(0, isolate->factory()->empty_string());
int position = 0;
i::Handle<i::Script> i_script(
i::Script::cast(v8::Utils::OpenHandle(*script)->shared()->script()));
isolate->debug()->SetBreakPointForScript(i_script, break_point, &position);
break_point_hit_count = 0;
v8::Local<v8::Value> r = script->Run(context).ToLocalChecked();
......@@ -5717,48 +4867,6 @@ TEST(ExceptionEventWhenEventListenerIsReset) {
}
// Tests after compile event is sent when there are some provisional
// breakpoints out of the scripts lines range.
TEST(ProvisionalBreakpointOnLineOutOfRange) {
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
env.ExposeDebug();
const char* script = "function f() {};";
const char* resource_name = "test_resource";
SetDebugEventListener(env->GetIsolate(), AfterCompileEventListener);
v8::Local<v8::Context> context = env.context();
// Set a couple of provisional breakpoint on lines out of the script lines
// range.
int sbp1 = SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name,
3, -1 /* no column */);
int sbp2 =
SetScriptBreakPointByNameFromJS(env->GetIsolate(), resource_name, 5, 5);
after_compile_event_count = 0;
v8::ScriptOrigin origin(v8_str(env->GetIsolate(), resource_name),
v8::Integer::New(env->GetIsolate(), 10),
v8::Integer::New(env->GetIsolate(), 1));
// Compile a script whose first line number is greater than the breakpoints'
// lines.
v8::Script::Compile(context, v8_str(env->GetIsolate(), script), &origin)
.ToLocalChecked()
->Run(context)
.ToLocalChecked();
// If the script is compiled successfully there is exactly one after compile
// event. In case of an exception in debugger code after compile event is not
// sent.
CHECK_EQ(1, after_compile_event_count);
ClearBreakPointFromJS(env->GetIsolate(), sbp1);
ClearBreakPointFromJS(env->GetIsolate(), sbp2);
SetDebugEventListener(env->GetIsolate(), nullptr);
CheckDebuggerUnloaded();
}
static void BreakEventListener(const v8::Debug::EventDetails& details) {
if (details.GetEvent() == v8::Break) break_point_hit_count++;
}
......
......@@ -88,7 +88,6 @@ class BreakHandler : public debug::DebugDelegate {
void BreakProgramRequested(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object> exec_state,
v8::Local<v8::Value> break_points_hit,
const std::vector<int>&) override {
printf("Break #%d\n", count_);
CHECK_GT(expected_breaks_.size(), count_);
......@@ -114,26 +113,6 @@ class BreakHandler : public debug::DebugDelegate {
}
};
Handle<JSObject> MakeFakeBreakpoint(Isolate* isolate, int position) {
Handle<JSObject> obj =
isolate->factory()->NewJSObject(isolate->object_function());
// Generate an "isTriggered" method that always returns true.
// This can/must be refactored once we remove remaining JS parts from the
// debugger (bug 5530).
Handle<String> source = isolate->factory()->NewStringFromStaticChars("true");
Handle<Context> context(isolate->context(), isolate);
Handle<JSFunction> triggered_fun =
Compiler::GetFunctionFromString(context, source, NO_PARSE_RESTRICTION,
kNoSourcePosition)
.ToHandleChecked();
PropertyDescriptor desc;
desc.set_value(triggered_fun);
Handle<String> name =
isolate->factory()->InternalizeUtf8String(CStrVector("isTriggered"));
CHECK(JSObject::DefineOwnProperty(isolate, obj, name, &desc, kDontThrow)
.FromMaybe(false));
return obj;
}
void SetBreakpoint(WasmRunnerBase& runner, int function_index, int byte_offset,
int expected_set_byte_offset = -1) {
......@@ -143,10 +122,12 @@ void SetBreakpoint(WasmRunnerBase& runner, int function_index, int byte_offset,
if (expected_set_byte_offset == -1) expected_set_byte_offset = byte_offset;
Handle<WasmInstanceObject> instance = runner.builder().instance_object();
Handle<WasmCompiledModule> compiled_module(instance->compiled_module());
Handle<JSObject> fake_breakpoint_object =
MakeFakeBreakpoint(runner.main_isolate(), code_offset);
static int break_index = 0;
Handle<BreakPoint> break_point =
runner.main_isolate()->factory()->NewBreakPoint(
break_index++, runner.main_isolate()->factory()->empty_string());
CHECK(WasmCompiledModule::SetBreakPoint(compiled_module, &code_offset,
fake_breakpoint_object));
break_point));
int set_byte_offset = code_offset - func_offset;
CHECK_EQ(expected_set_byte_offset, set_byte_offset);
// Also set breakpoint on the debug info of the instance directly, since the
......@@ -212,7 +193,6 @@ class CollectValuesBreakHandler : public debug::DebugDelegate {
void BreakProgramRequested(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object> exec_state,
v8::Local<v8::Value> break_points_hit,
const std::vector<int>&) override {
printf("Break #%d\n", count_);
CHECK_GT(expected_values_.size(), count_);
......
......@@ -5,7 +5,7 @@
// Flags: --allow-natives-syntax --cache=code
// Test that script ids are unique and we found the correct ones.
var Debug = %GetDebugContext().Debug;
var Debug = debug.Debug;
Debug.setListener(function(){});
var scripts = %DebugGetLoadedScripts();
......
// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Test that setting break point works correctly when the debugger is
// activated late, which leads to duplicate shared function infos.
(function() {
var Debug = %GetDebugContext().Debug;
function listener(event, exec_state, event_data, data) {
if (event != Debug.DebugEvent.Break) return;
try {
assertTrue(/foo/.test(exec_state.frame(0).sourceLineText()));
break_count++;
} catch (e) {
exception = e;
}
}
for (var i = 0; i < 3; i++) {
var foo = function() { a = 1; }
var exception = null;
var break_count = 0;
Debug.setListener(listener);
if (i < 2) Debug.setBreakPoint(foo, 0, 0);
assertTrue(/\[B\d\]a = 1/.test(Debug.showBreakPoints(foo)));
foo();
assertEquals(1, break_count);
assertNull(exception);
}
Debug.setListener(null);
})();
......@@ -7,7 +7,7 @@
try { } catch(e) { }
try { try { } catch (e) { } } catch(e) { }
try {
var Debug = %GetDebugContext().Debug;
var Debug = debug.Debug;
Debug.setListener(function(){});
} catch(e) { }
(function() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment