Commit cd9e86a5 authored by Alexey Kozyatinskiy's avatar Alexey Kozyatinskiy Committed by Commit Bot

[inspector] move breakpoint management to native

My goal was to move breakpoint API to native with minimal changes around, so on inspector side we use v8::debug::BreakpointId instead of String16, on v8::internal::Debug we use i::BreakPoint object instead of break point object created inside of debug.js.

There are a lot of opportunities how we can improve breakpoints (at least we can avoid some of linear lookups to speedup implementation) but I think that as first step we need to remove mirrors/debug.js APIs.

Drive by: debugger-script.js and usage of debugger context in inspector code base.

R=yangguo@chromium.org,jgruber@chromium.org,clemensh@chromium.org

Bug: v8:5510,chromium:652939
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_chromium_rel_ng
Change-Id: I0b17972c39053dd4989bbe26db2bb0b88ca378f7
Reviewed-on: https://chromium-review.googlesource.com/593156Reviewed-by: 's avatarClemens Hammacher <clemensh@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Aleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47091}
parent 41daf8a5
......@@ -9636,8 +9636,9 @@ bool debug::Script::GetPossibleBreakpoints(
int debug::Script::GetSourceOffset(const debug::Location& location) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
if (script->type() == i::Script::TYPE_WASM) {
// TODO(clemensh): Return the proper thing for wasm.
return 0;
return i::WasmCompiledModule::cast(script->wasm_compiled_module())
->GetFunctionOffset(location.GetLineNumber()) +
location.GetColumnNumber();
}
int line = std::max(location.GetLineNumber() - script->line_offset(), 0);
......@@ -9674,6 +9675,26 @@ bool debug::Script::SetScriptSource(v8::Local<v8::String> newSource,
script, Utils::OpenHandle(*newSource), preview, stack_changed);
}
bool debug::Script::SetBreakpoint(v8::Local<v8::String> condition,
debug::Location* location,
debug::BreakpointId* id) const {
i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate();
int offset = GetSourceOffset(*location);
if (!isolate->debug()->SetBreakpoint(script, Utils::OpenHandle(*condition),
&offset, id)) {
return false;
}
*location = GetSourceLocation(offset);
return true;
}
void debug::RemoveBreakpoint(Isolate* v8_isolate, BreakpointId id) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
i::HandleScope handle_scope(isolate);
isolate->debug()->RemoveBreakpoint(id);
}
debug::WasmScript* debug::WasmScript::Cast(debug::Script* script) {
CHECK(script->IsWasm());
return static_cast<WasmScript*>(script);
......
......@@ -94,6 +94,7 @@ enum ExceptionBreakState {
*/
void ChangeBreakOnException(Isolate* isolate, ExceptionBreakState state);
void RemoveBreakpoint(Isolate* isolate, BreakpointId id);
void SetBreakPointsActive(Isolate* isolate, bool is_active);
enum StepAction {
......@@ -148,6 +149,8 @@ class V8_EXPORT_PRIVATE Script {
v8::debug::Location GetSourceLocation(int offset) const;
bool SetScriptSource(v8::Local<v8::String> newSource, bool preview,
bool* stack_changed) const;
bool SetBreakpoint(v8::Local<v8::String> condition, debug::Location* location,
BreakpointId* id) const;
};
// Specialization for wasm Scripts.
......@@ -175,9 +178,13 @@ class DebugDelegate {
int parent_id, bool created_by_user) {}
virtual void ScriptCompiled(v8::Local<Script> script, bool is_live_edited,
bool has_compile_error) {}
virtual void BreakProgramRequested(v8::Local<v8::Context> paused_context,
v8::Local<v8::Object> exec_state,
v8::Local<v8::Value> break_points_hit) {}
// |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,
v8::Local<v8::Value> exception,
......
......@@ -381,6 +381,7 @@ void Debug::ThreadInit() {
thread_local_.target_frame_count_ = -1;
thread_local_.return_value_ = Smi::kZero;
thread_local_.async_task_count_ = 0;
thread_local_.last_breakpoint_id_ = 0;
clear_suspended_generator();
thread_local_.restart_fp_ = nullptr;
base::Relaxed_Store(&thread_local_.current_debug_scope_,
......@@ -507,9 +508,7 @@ void Debug::Break(JavaScriptFrame* frame) {
// Clear all current stepping setup.
ClearStepping();
// Notify the debug event listeners.
Handle<JSArray> jsarr = isolate_->factory()->NewJSArrayWithElements(
break_points_hit.ToHandleChecked());
OnDebugBreak(jsarr);
OnDebugBreak(break_points_hit.ToHandleChecked());
return;
}
......@@ -558,7 +557,7 @@ void Debug::Break(JavaScriptFrame* frame) {
if (step_break) {
// Notify the debug event listeners.
OnDebugBreak(isolate_->factory()->undefined_value());
OnDebugBreak(isolate_->factory()->empty_fixed_array());
} else {
// Re-prepare to continue.
PrepareStep(step_action);
......@@ -638,6 +637,27 @@ bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
Factory* factory = isolate_->factory();
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;
......@@ -798,6 +818,20 @@ void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
}
}
bool Debug::SetBreakpoint(Handle<Script> script, Handle<String> condition,
int* offset, int* id) {
*id = ++thread_local_.last_breakpoint_id_;
Handle<BreakPoint> breakpoint =
isolate_->factory()->NewBreakPoint(*id, condition);
return SetBreakPointForScript(script, breakpoint, offset);
}
void Debug::RemoveBreakpoint(int id) {
Handle<BreakPoint> breakpoint = isolate_->factory()->NewBreakPoint(
id, isolate_->factory()->empty_string());
ClearBreakPoint(breakpoint);
}
// Clear out all the debug break code.
void Debug::ClearAllBreakPoints() {
ClearAllDebugInfos([=](Handle<DebugInfo> info) {
......@@ -1879,7 +1913,8 @@ void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
v8::Utils::ToLocal(exception), v8::Utils::ToLocal(promise), uncaught);
}
void Debug::OnDebugBreak(Handle<Object> break_points_hit) {
void Debug::OnDebugBreak(Handle<FixedArray> break_points_hit) {
DCHECK(!break_points_hit.is_null());
// The caller provided for DebugScope.
AssertDebugContext();
// Bail out if there is no listener for this event
......@@ -1899,10 +1934,33 @@ void Debug::OnDebugBreak(Handle<Object> break_points_hit) {
// Bail out and don't call debugger if exception.
if (!MakeExecutionState().ToHandle(&exec_state)) return;
std::vector<int> inspector_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();
}
debug_delegate_->BreakProgramRequested(
GetDebugEventContext(isolate_),
v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
v8::Utils::ToLocal(break_points_hit));
v8::Utils::ToLocal(break_points), inspector_break_points_hit);
}
......@@ -2240,7 +2298,7 @@ void Debug::HandleDebugBreak(IgnoreBreakMode ignore_break_mode) {
DebugScope debug_scope(this);
if (debug_scope.failed()) return;
OnDebugBreak(isolate_->factory()->undefined_value());
OnDebugBreak(isolate_->factory()->empty_fixed_array());
}
#ifdef DEBUG
......@@ -2386,7 +2444,8 @@ 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) {
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))
......
......@@ -256,7 +256,7 @@ class DebugFeatureTracker {
class Debug {
public:
// Debug event triggers.
void OnDebugBreak(Handle<Object> break_points_hit);
void OnDebugBreak(Handle<FixedArray> break_points_hit);
void OnThrow(Handle<Object> exception);
void OnPromiseReject(Handle<Object> promise, Handle<Object> value);
......@@ -288,6 +288,10 @@ class Debug {
void ChangeBreakOnException(ExceptionBreakType type, bool enable);
bool IsBreakOnException(ExceptionBreakType type);
bool SetBreakpoint(Handle<Script> script, Handle<String> condition,
int* offset, int* id);
void RemoveBreakpoint(int id);
// The parameter is either a BreakPointInfo object, or a FixedArray of
// BreakPointInfo objects.
// Returns an empty handle if no breakpoint is hit, or a FixedArray with all
......@@ -596,6 +600,9 @@ class Debug {
Address restart_fp_;
int async_task_count_;
// Last used inspector breakpoint id.
int last_breakpoint_id_;
};
// Storage location for registers when handling debug break calls
......@@ -626,7 +633,8 @@ 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) override;
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,
v8::Local<v8::Value> exception,
......
......@@ -170,6 +170,8 @@ class ConsoleDelegate {
virtual ~ConsoleDelegate() = default;
};
typedef int BreakpointId;
} // namespace debug
} // namespace v8
......
......@@ -2688,6 +2688,14 @@ Handle<BreakPointInfo> Factory::NewBreakPointInfo(int source_position) {
return new_break_point_info;
}
Handle<BreakPoint> Factory::NewBreakPoint(int id, Handle<String> condition) {
Handle<BreakPoint> new_break_point =
Handle<BreakPoint>::cast(NewStruct(TUPLE2_TYPE));
new_break_point->set_id(id);
new_break_point->set_condition(*condition);
return new_break_point;
}
Handle<StackFrameInfo> Factory::NewStackFrameInfo() {
Handle<StackFrameInfo> stack_frame_info =
Handle<StackFrameInfo>::cast(NewStruct(STACK_FRAME_INFO_TYPE));
......
......@@ -20,6 +20,7 @@ namespace internal {
class AliasedArgumentsEntry;
class BreakPointInfo;
class BreakPoint;
class BoilerplateDescription;
class ConstantElementsPair;
class CoverageInfo;
......@@ -365,6 +366,7 @@ class V8_EXPORT_PRIVATE Factory final {
Handle<Script> NewScript(Handle<String> source);
Handle<BreakPointInfo> NewBreakPointInfo(int source_position);
Handle<BreakPoint> NewBreakPoint(int id, Handle<String> condition);
Handle<StackFrameInfo> NewStackFrameInfo();
Handle<SourcePositionTableWithFrameCache>
NewSourcePositionTableWithFrameCache(
......
......@@ -77,22 +77,6 @@ action("inspector_injected_script") {
]
}
action("inspector_debugger_script") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
script = "build/xxd.py"
inputs = [
"debugger-script.js",
]
outputs = [
"$target_gen_dir/debugger-script.h",
]
args = [
"DebuggerScript_js",
rebase_path("debugger-script.js", root_build_dir),
rebase_path("$target_gen_dir/debugger-script.h", root_build_dir),
]
}
config("inspector_config") {
visibility = [ ":*" ] # Only targets in this file can depend on this.
cflags = []
......@@ -113,7 +97,6 @@ config("inspector_config") {
v8_source_set("inspector") {
deps = [
":inspector_debugger_script",
":inspector_injected_script",
":protocol_generated_sources",
]
......@@ -130,7 +113,6 @@ v8_source_set("inspector") {
"../../include/v8-inspector.h",
]
sources += get_target_outputs(":inspector_injected_script")
sources += get_target_outputs(":inspector_debugger_script")
sources += [
"injected-script.cc",
"injected-script.h",
......@@ -181,8 +163,8 @@ v8_source_set("inspector") {
"v8-schema-agent-impl.h",
"v8-stack-trace-impl.cc",
"v8-stack-trace-impl.h",
"v8-value-copier.cc",
"v8-value-copier.h",
"v8-value-utils.cc",
"v8-value-utils.h",
"wasm-translation.cc",
"wasm-translation.h",
]
......
......@@ -20,10 +20,8 @@ def _CompileScripts(input_api, output_api):
"js_protocol.json"
"compile-scripts.js",
"injected-script-source.js",
"debugger_script_externs.js",
"injected_script_externs.js",
"check_injected_script_source.js",
"debugger-script.js"
"check_injected_script_source.js"
]
for file in compilation_related_files:
......
......@@ -25,10 +25,6 @@ injected_script_source_name = path.join(v8_inspector_path,
'injected-script-source.js')
injected_script_externs_file = path.join(v8_inspector_path,
'injected_script_externs.js')
debugger_script_source_name = path.join(v8_inspector_path,
'debugger-script.js')
debugger_script_externs_file = path.join(v8_inspector_path,
'debugger_script_externs.js')
generate_protocol_externs.generate_protocol_externs(protocol_externs_file,
path.join(v8_inspector_path, 'js_protocol.json'))
......@@ -129,16 +125,6 @@ command = spawned_compiler_command + [
injected_script_compile_proc = popen(command)
print 'Compiling debugger-script.js...'
command = spawned_compiler_command + [
'--externs', debugger_script_externs_file,
'--js', debugger_script_source_name,
'--new_type_inf'
]
debugger_script_compile_proc = popen(command)
print 'Validating injected-script-source.js...'
injectedscript_check_script_path = path.join(v8_inspector_path, 'build',
'check_injected_script_source.py')
......@@ -152,11 +138,6 @@ print 'injected-script-source.js compilation output:%s' % os.linesep
print injected_script_compile_out
errors_found |= has_errors(injected_script_compile_out)
(debugger_script_compiler_out, _) = debugger_script_compile_proc.communicate()
print 'debugger-script.js compilation output:%s' % os.linesep
print debugger_script_compiler_out
errors_found |= has_errors(debugger_script_compiler_out)
(validate_injected_script_out, _) = validate_injected_script_proc.communicate()
print 'Validate injected-script-source.js output:%s' % os.linesep
print validate_injected_script_out if validate_injected_script_out else '<empty>'
......
/*
* Copyright (C) 2010 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
"use strict";
(function () {
var DebuggerScript = {};
/**
* @param {!ExecutionState} execState
* @param {!BreakpointInfo} info
* @return {string|undefined}
*/
DebuggerScript.setBreakpoint = function(execState, info)
{
var breakId = Debug.setScriptBreakPointById(info.sourceID, info.lineNumber, info.columnNumber, info.condition, undefined);
var locations = Debug.findBreakPointActualLocations(breakId);
if (!locations.length)
return undefined;
info.lineNumber = locations[0].line;
info.columnNumber = locations[0].column;
return breakId.toString();
}
/**
* @param {!ExecutionState} execState
* @param {!{breakpointId: number}} info
*/
DebuggerScript.removeBreakpoint = function(execState, info)
{
Debug.findBreakPoint(info.breakpointId, true);
}
/**
* @param {!Array<!BreakPoint>|undefined} breakpoints
*/
DebuggerScript.getBreakpointNumbers = function(breakpoints)
{
var numbers = [];
if (!breakpoints)
return numbers;
for (var i = 0; i < breakpoints.length; i++) {
var breakpoint = breakpoints[i];
var scriptBreakPoint = breakpoint.script_break_point();
numbers.push(scriptBreakPoint ? scriptBreakPoint.number() : breakpoint.number());
}
return numbers;
}
return DebuggerScript;
})();
// Copyright 2016 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.
/**
* @const
*/
var Debug = {};
/** @return {!Array<!Script>} */
Debug.scripts = function() {}
/**
* @param {number} scriptId
* @param {number=} line
* @param {number=} column
* @param {string=} condition
* @param {string=} groupId
*/
Debug.setScriptBreakPointById = function(scriptId, line, column, condition, groupId) {}
/** @typedef {{
* script: number,
* position: number,
* line: number,
* column:number,
* start: number,
* end: number,
* }}
*/
var SourceLocation;
/**
* @param {number} breakId
* @return {!Array<!SourceLocation>}
*/
Debug.findBreakPointActualLocations = function(breakId) {}
/**
* @param {number} breakId
* @param {boolean} remove
* @return {!BreakPoint|undefined}
*/
Debug.findBreakPoint = function(breakId, remove) {}
/** @typedef {{
* breakpointId: number,
* sourceID: number,
* lineNumber: (number|undefined),
* columnNumber: (number|undefined),
* condition: (string|undefined),
* interstatementLocation: (boolean|undefined),
* }}
*/
var BreakpointInfo;
/** @interface */
function BreakPoint() {}
/** @return {!BreakPoint|undefined} */
BreakPoint.prototype.script_break_point = function() {}
/** @return {number} */
BreakPoint.prototype.number = function() {}
/** @interface */
function ExecutionState() {}
/** @typedef{{
* id: number,
* }}
*/
var Script;
......@@ -41,7 +41,7 @@
#include "src/inspector/v8-inspector-impl.h"
#include "src/inspector/v8-inspector-session-impl.h"
#include "src/inspector/v8-stack-trace-impl.h"
#include "src/inspector/v8-value-copier.h"
#include "src/inspector/v8-value-utils.h"
#include "include/v8-inspector.h"
......
......@@ -9,7 +9,6 @@
#include "src/inspector/string-util.h"
#include "src/inspector/v8-console.h"
#include "src/inspector/v8-inspector-impl.h"
#include "src/inspector/v8-value-copier.h"
#include "include/v8-inspector.h"
......
......@@ -36,31 +36,6 @@
# Since this target generates header files, it needs to be a hard dependency.
'hard_dependency': 1,
},
{ 'target_name': 'inspector_debugger_script',
'type': 'none',
'toolsets': ['target'],
'actions': [
{
'action_name': 'convert_js_to_cpp_char_array',
'inputs': [
'build/xxd.py',
'<(inspector_debugger_script_source)',
],
'outputs': [
'<(inspector_generated_debugger_script)',
],
'action': [
'python',
'build/xxd.py',
'DebuggerScript_js',
'debugger-script.js',
'<@(_outputs)'
],
},
],
# Since this target generates header files, it needs to be a hard dependency.
'hard_dependency': 1,
},
{ 'target_name': 'protocol_compatibility',
'type': 'none',
'toolsets': ['target'],
......
......@@ -27,13 +27,10 @@
'inspector_injected_script_source': 'injected-script-source.js',
'inspector_generated_injected_script': '<(SHARED_INTERMEDIATE_DIR)/src/inspector/injected-script-source.h',
'inspector_debugger_script_source': 'debugger-script.js',
'inspector_generated_debugger_script': '<(SHARED_INTERMEDIATE_DIR)/src/inspector/debugger-script.h',
'inspector_all_sources': [
'<@(inspector_generated_sources)',
'<(inspector_generated_injected_script)',
'<(inspector_generated_debugger_script)',
'../../include/v8-inspector.h',
'../../include/v8-inspector-protocol.h',
'inspector/injected-script.cc',
......@@ -85,8 +82,8 @@
'inspector/v8-schema-agent-impl.h',
'inspector/v8-stack-trace-impl.cc',
'inspector/v8-stack-trace-impl.h',
'inspector/v8-value-copier.cc',
'inspector/v8-value-copier.h',
'inspector/v8-value-utils.cc',
'inspector/v8-value-utils.h',
'inspector/wasm-translation.cc',
'inspector/wasm-translation.h',
]
......
......@@ -15,7 +15,7 @@
#include "src/inspector/v8-profiler-agent-impl.h"
#include "src/inspector/v8-runtime-agent-impl.h"
#include "src/inspector/v8-stack-trace-impl.h"
#include "src/inspector/v8-value-copier.h"
#include "src/inspector/v8-value-utils.h"
#include "include/v8-inspector.h"
......
......@@ -21,7 +21,7 @@
#include "src/inspector/v8-regex.h"
#include "src/inspector/v8-runtime-agent-impl.h"
#include "src/inspector/v8-stack-trace-impl.h"
#include "src/inspector/v8-value-copier.h"
#include "src/inspector/v8-value-utils.h"
#include "include/v8-inspector.h"
......@@ -538,14 +538,12 @@ void V8DebuggerAgentImpl::removeBreakpointImpl(const String16& breakpointId) {
debuggerBreakpointIdsIterator =
m_breakpointIdToDebuggerBreakpointIds.find(breakpointId);
if (debuggerBreakpointIdsIterator ==
m_breakpointIdToDebuggerBreakpointIds.end())
m_breakpointIdToDebuggerBreakpointIds.end()) {
return;
const std::vector<String16>& ids = debuggerBreakpointIdsIterator->second;
for (size_t i = 0; i < ids.size(); ++i) {
const String16& debuggerBreakpointId = ids[i];
m_debugger->removeBreakpoint(debuggerBreakpointId);
m_serverBreakpoints.erase(debuggerBreakpointId);
}
for (const auto& id : debuggerBreakpointIdsIterator->second) {
v8::debug::RemoveBreakpoint(m_isolate, id);
m_serverBreakpoints.erase(id);
}
m_breakpointIdToDebuggerBreakpointIds.erase(breakpointId);
}
......@@ -610,8 +608,18 @@ Response V8DebuggerAgentImpl::continueToLocation(
Maybe<String16> targetCallFrames) {
if (!enabled()) return Response::Error(kDebuggerNotEnabled);
if (!isPaused()) return Response::Error(kDebuggerNotPaused);
ScriptsMap::iterator it = m_scripts.find(location->getScriptId());
if (it == m_scripts.end()) {
return Response::Error("Cannot continue to specified location");
}
V8DebuggerScript* script = it->second.get();
int contextId = script->executionContextId();
InspectedContext* inspected = m_inspector->getContext(contextId);
if (!inspected)
return Response::Error("Cannot continue to specified location");
v8::Context::Scope contextScope(inspected->context());
return m_debugger->continueToLocation(
m_session->contextGroupId(), std::move(location),
m_session->contextGroupId(), script, std::move(location),
targetCallFrames.fromMaybe(
protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any));
}
......@@ -666,23 +674,34 @@ V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId,
CHECK(!breakpoint.script_id.isEmpty());
ScriptsMap::iterator scriptIterator = m_scripts.find(breakpoint.script_id);
if (scriptIterator == m_scripts.end()) return nullptr;
if (breakpoint.line_number < scriptIterator->second->startLine() ||
scriptIterator->second->endLine() < breakpoint.line_number)
V8DebuggerScript* script = scriptIterator->second.get();
if (breakpoint.line_number < script->startLine() ||
script->endLine() < breakpoint.line_number)
return nullptr;
// Translate from protocol location to v8 location for the debugger.
ScriptBreakpoint translatedBreakpoint = breakpoint;
adjustBreakpointLocation(*scriptIterator->second, hint,
&translatedBreakpoint);
adjustBreakpointLocation(*script, hint, &translatedBreakpoint);
m_debugger->wasmTranslation()->TranslateProtocolLocationToWasmScriptLocation(
&translatedBreakpoint.script_id, &translatedBreakpoint.line_number,
&translatedBreakpoint.column_number);
int actualLineNumber;
int actualColumnNumber;
String16 debuggerBreakpointId = m_debugger->setBreakpoint(
translatedBreakpoint, &actualLineNumber, &actualColumnNumber);
if (debuggerBreakpointId.isEmpty()) return nullptr;
v8::debug::BreakpointId debuggerBreakpointId;
v8::debug::Location location(translatedBreakpoint.line_number,
translatedBreakpoint.column_number);
int contextId = script->executionContextId();
InspectedContext* inspected = m_inspector->getContext(contextId);
if (!inspected) return nullptr;
{
v8::Context::Scope contextScope(inspected->context());
if (!script->setBreakpoint(translatedBreakpoint.condition, &location,
&debuggerBreakpointId)) {
return nullptr;
}
}
int actualLineNumber = location.GetLineNumber();
int actualColumnNumber = location.GetColumnNumber();
// Translate back from v8 location to protocol location for the return value.
m_debugger->wasmTranslation()->TranslateWasmScriptLocationToProtocolLocation(
......@@ -734,9 +753,7 @@ Response V8DebuggerAgentImpl::setScriptSource(
return Response::Error("Editing module's script is not supported.");
}
int contextId = it->second->executionContextId();
int contextGroupId = m_inspector->contextGroupId(contextId);
InspectedContext* inspected =
m_inspector->getContext(contextGroupId, contextId);
InspectedContext* inspected = m_inspector->getContext(contextId);
if (!inspected) {
return Response::InternalError();
}
......@@ -1251,11 +1268,10 @@ void V8DebuggerAgentImpl::didParseSource(
}
}
void V8DebuggerAgentImpl::didPause(int contextId,
v8::Local<v8::Value> exception,
const std::vector<String16>& hitBreakpoints,
bool isPromiseRejection, bool isUncaught,
bool isOOMBreak, bool isAssert) {
void V8DebuggerAgentImpl::didPause(
int contextId, v8::Local<v8::Value> exception,
const std::vector<v8::debug::BreakpointId>& hitBreakpoints,
bool isPromiseRejection, bool isUncaught, bool isOOMBreak, bool isAssert) {
v8::HandleScope handles(m_isolate);
std::vector<BreakReason> hitReasons;
......@@ -1292,9 +1308,9 @@ void V8DebuggerAgentImpl::didPause(int contextId,
std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create();
bool hasDebugCommandBreakpointReason = false;
for (const auto& point : hitBreakpoints) {
for (const auto& id : hitBreakpoints) {
DebugServerBreakpointToBreakpointIdAndSourceMap::iterator
breakpointIterator = m_serverBreakpoints.find(point);
breakpointIterator = m_serverBreakpoints.find(id);
if (breakpointIterator != m_serverBreakpoints.end()) {
const String16& localId = breakpointIterator->second.first;
hitBreakpointIds->addItem(localId);
......
......@@ -126,7 +126,7 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
// Interface for V8InspectorImpl
void didPause(int contextId, v8::Local<v8::Value> exception,
const std::vector<String16>& hitBreakpoints,
const std::vector<v8::debug::BreakpointId>& hitBreakpoints,
bool isPromiseRejection, bool isUncaught, bool isOOMBreak,
bool isAssert);
void didContinue();
......@@ -166,9 +166,10 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
using ScriptsMap =
protocol::HashMap<String16, std::unique_ptr<V8DebuggerScript>>;
using BreakpointIdToDebuggerBreakpointIdsMap =
protocol::HashMap<String16, std::vector<String16>>;
protocol::HashMap<String16, std::vector<v8::debug::BreakpointId>>;
using DebugServerBreakpointToBreakpointIdAndSourceMap =
protocol::HashMap<String16, std::pair<String16, BreakpointSource>>;
protocol::HashMap<v8::debug::BreakpointId,
std::pair<String16, BreakpointSource>>;
using MuteBreakpoins = protocol::HashMap<String16, std::pair<String16, int>>;
V8InspectorImpl* m_inspector;
......
......@@ -237,6 +237,10 @@ class ActualScript : public V8DebuggerScript {
return String16();
}
v8::Local<v8::debug::Script> script() const override {
return m_script.Get(m_isolate);
}
String16 m_sourceMappingURL;
bool m_isLiveEdit = false;
bool m_isModule = false;
......@@ -264,6 +268,7 @@ class WasmVirtualScript : public V8DebuggerScript {
m_endLine = num_lines;
m_endColumn = static_cast<int>(source.length()) - last_newline - 1;
m_source = std::move(source);
m_executionContextId = script->ContextId().ToChecked();
}
const String16& sourceMappingURL() const override { return emptyString(); }
......@@ -319,6 +324,10 @@ class WasmVirtualScript : public V8DebuggerScript {
return singleEmptyString;
}
v8::Local<v8::debug::Script> script() const override {
return m_script.Get(m_isolate);
}
v8::Global<v8::debug::WasmScript> m_script;
WasmTranslation* m_wasmTranslation;
};
......@@ -361,4 +370,10 @@ void V8DebuggerScript::setSourceURL(const String16& sourceURL) {
m_sourceURL = sourceURL;
}
bool V8DebuggerScript::setBreakpoint(const String16& condition,
v8::debug::Location* loc, int* id) const {
v8::HandleScope scope(m_isolate);
return script()->SetBreakpoint(toV8String(m_isolate, condition), loc, id);
}
} // namespace v8_inspector
......@@ -84,9 +84,14 @@ class V8DebuggerScript {
virtual int offset(int lineNumber, int columnNumber) const = 0;
virtual v8::debug::Location location(int offset) const = 0;
bool setBreakpoint(const String16& condition, v8::debug::Location* location,
int* id) const;
protected:
V8DebuggerScript(v8::Isolate*, String16 id, String16 url);
virtual v8::Local<v8::debug::Script> script() const = 0;
String16 m_id;
String16 m_url;
String16 m_sourceURL;
......
This diff is collapsed.
......@@ -40,9 +40,6 @@ class V8Debugger : public v8::debug::DebugDelegate {
bool enabled() const;
v8::Isolate* isolate() const { return m_isolate; }
String16 setBreakpoint(const ScriptBreakpoint&, int* actualLineNumber,
int* actualColumnNumber);
void removeBreakpoint(const String16& breakpointId);
void setBreakpointsActive(bool);
v8::debug::ExceptionBreakState getPauseOnExceptionsState();
......@@ -61,6 +58,7 @@ class V8Debugger : public v8::debug::DebugDelegate {
int targetContextGroupId);
Response continueToLocation(int targetContextGroupId,
V8DebuggerScript* script,
std::unique_ptr<protocol::Debugger::Location>,
const String16& targetCallFramess);
......@@ -75,7 +73,6 @@ class V8Debugger : public v8::debug::DebugDelegate {
bool isPaused() const { return m_pausedContextGroupId; }
bool isPausedInContextGroup(int contextGroupId) const;
v8::Local<v8::Context> pausedContext() { return m_pausedContext; }
int maxAsyncCallChainDepth() { return m_maxAsyncCallStackDepth; }
void setAsyncCallStackDepth(V8DebuggerAgentImpl*, int);
......@@ -109,23 +106,15 @@ class V8Debugger : public v8::debug::DebugDelegate {
void dumpAsyncTaskStacksStateForTest();
private:
void compileDebuggerScript();
v8::MaybeLocal<v8::Value> callDebuggerMethod(const char* functionName,
int argc,
v8::Local<v8::Value> argv[],
bool catchExceptions);
v8::Local<v8::Context> debuggerContext() const;
void clearContinueToLocation();
bool shouldContinueToCurrentLocation();
static void v8OOMCallback(void* data);
void handleProgramBreak(v8::Local<v8::Context> pausedContext,
v8::Local<v8::Object> executionState,
v8::Local<v8::Value> exception,
v8::Local<v8::Array> hitBreakpoints,
bool isPromiseRejection = false,
bool isUncaught = false);
void handleProgramBreak(
v8::Local<v8::Context> pausedContext, v8::Local<v8::Value> exception,
const std::vector<v8::debug::BreakpointId>& hitBreakpoints,
bool isPromiseRejection = false, bool isUncaught = false);
enum ScopeTargetKind {
FUNCTION,
......@@ -157,12 +146,12 @@ class V8Debugger : public v8::debug::DebugDelegate {
int parentId, bool createdByUser) override;
void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited,
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) 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> exec_state,
v8::Local<v8::Value> exception,
v8::Local<v8::Object>, v8::Local<v8::Value> exception,
v8::Local<v8::Value> promise, bool is_uncaught) override;
bool IsFunctionBlackboxed(v8::Local<v8::debug::Script> script,
const v8::debug::Location& start,
......@@ -174,16 +163,12 @@ class V8Debugger : public v8::debug::DebugDelegate {
V8InspectorImpl* m_inspector;
int m_enableCount;
int m_breakpointsActiveCount = 0;
v8::Global<v8::Object> m_debuggerScript;
v8::Global<v8::Context> m_debuggerContext;
v8::Local<v8::Object> m_executionState;
v8::Local<v8::Context> m_pausedContext;
int m_ignoreScriptParsedEventsCounter;
bool m_scheduledOOMBreak = false;
bool m_scheduledAssertBreak = false;
int m_targetContextGroupId = 0;
int m_pausedContextGroupId = 0;
String16 m_continueToLocationBreakpointId;
int m_continueToLocationBreakpointId;
String16 m_continueToLocationTargetCallFrames;
std::unique_ptr<V8StackTraceImpl> m_continueToLocationStack;
......
......@@ -10,7 +10,7 @@
#include "src/inspector/v8-debugger.h"
#include "src/inspector/v8-inspector-impl.h"
#include "src/inspector/v8-internal-value-type.h"
#include "src/inspector/v8-value-copier.h"
#include "src/inspector/v8-value-utils.h"
#include "include/v8-inspector.h"
......
......@@ -66,13 +66,12 @@ V8InspectorImpl::~V8InspectorImpl() {
v8::debug::SetConsoleDelegate(m_isolate, nullptr);
}
int V8InspectorImpl::contextGroupId(v8::Local<v8::Context> context) {
int V8InspectorImpl::contextGroupId(v8::Local<v8::Context> context) const {
return contextGroupId(InspectedContext::contextId(context));
}
int V8InspectorImpl::contextGroupId(int contextId) {
protocol::HashMap<int, int>::iterator it =
m_contextIdToGroupIdMap.find(contextId);
int V8InspectorImpl::contextGroupId(int contextId) const {
auto it = m_contextIdToGroupIdMap.find(contextId);
return it != m_contextIdToGroupIdMap.end() ? it->second : 0;
}
......@@ -178,6 +177,10 @@ InspectedContext* V8InspectorImpl::getContext(int groupId,
return contextIt->second.get();
}
InspectedContext* V8InspectorImpl::getContext(int contextId) const {
return getContext(contextGroupId(contextId), contextId);
}
void V8InspectorImpl::contextCreated(const V8ContextInfo& info) {
int contextId = ++m_lastContextId;
InspectedContext* context = new InspectedContext(this, info, contextId);
......
......@@ -58,8 +58,8 @@ class V8InspectorImpl : public V8Inspector {
v8::Isolate* isolate() const { return m_isolate; }
V8InspectorClient* client() { return m_client; }
V8Debugger* debugger() { return m_debugger.get(); }
int contextGroupId(v8::Local<v8::Context>);
int contextGroupId(int contextId);
int contextGroupId(v8::Local<v8::Context>) const;
int contextGroupId(int contextId) const;
v8::MaybeLocal<v8::Value> compileAndRunInternalScript(v8::Local<v8::Context>,
v8::Local<v8::String>);
......@@ -107,6 +107,7 @@ class V8InspectorImpl : public V8Inspector {
void disconnect(V8InspectorSessionImpl*);
V8InspectorSessionImpl* sessionById(int contextGroupId, int sessionId);
InspectedContext* getContext(int groupId, int contextId) const;
InspectedContext* getContext(int contextId) const;
V8Console* console();
void forEachContext(int contextGroupId,
std::function<void(InspectedContext*)> callback);
......
......@@ -2,77 +2,12 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/inspector/v8-value-copier.h"
#include "src/inspector/v8-value-utils.h"
namespace v8_inspector {
namespace {
static int kMaxDepth = 20;
static int kMaxCalls = 1000;
class V8ValueCopier {
public:
v8::MaybeLocal<v8::Value> copy(v8::Local<v8::Value> value, int depth) {
if (++m_calls > kMaxCalls || depth > kMaxDepth)
return v8::MaybeLocal<v8::Value>();
if (value.IsEmpty()) return v8::MaybeLocal<v8::Value>();
if (value->IsNull() || value->IsUndefined() || value->IsBoolean() ||
value->IsString() || value->IsNumber())
return value;
if (!value->IsObject()) return v8::MaybeLocal<v8::Value>();
v8::Local<v8::Object> object = value.As<v8::Object>();
if (object->CreationContext() != m_from) return value;
if (object->IsArray()) {
v8::Local<v8::Array> array = object.As<v8::Array>();
v8::Local<v8::Array> result = v8::Array::New(m_isolate, array->Length());
if (!result->SetPrototype(m_to, v8::Null(m_isolate)).FromMaybe(false))
return v8::MaybeLocal<v8::Value>();
for (uint32_t i = 0; i < array->Length(); ++i) {
v8::Local<v8::Value> item;
if (!array->Get(m_from, i).ToLocal(&item))
return v8::MaybeLocal<v8::Value>();
v8::Local<v8::Value> copied;
if (!copy(item, depth + 1).ToLocal(&copied))
return v8::MaybeLocal<v8::Value>();
if (!createDataProperty(m_to, result, i, copied).FromMaybe(false))
return v8::MaybeLocal<v8::Value>();
}
return result;
}
v8::Local<v8::Object> result = v8::Object::New(m_isolate);
if (!result->SetPrototype(m_to, v8::Null(m_isolate)).FromMaybe(false))
return v8::MaybeLocal<v8::Value>();
v8::Local<v8::Array> properties;
if (!object->GetOwnPropertyNames(m_from).ToLocal(&properties))
return v8::MaybeLocal<v8::Value>();
for (uint32_t i = 0; i < properties->Length(); ++i) {
v8::Local<v8::Value> name;
if (!properties->Get(m_from, i).ToLocal(&name) || !name->IsString())
return v8::MaybeLocal<v8::Value>();
v8::Local<v8::Value> property;
if (!object->Get(m_from, name).ToLocal(&property))
return v8::MaybeLocal<v8::Value>();
v8::Local<v8::Value> copied;
if (!copy(property, depth + 1).ToLocal(&copied))
return v8::MaybeLocal<v8::Value>();
if (!createDataProperty(m_to, result, v8::Local<v8::String>::Cast(name),
copied)
.FromMaybe(false))
return v8::MaybeLocal<v8::Value>();
}
return result;
}
v8::Isolate* m_isolate;
v8::Local<v8::Context> m_from;
v8::Local<v8::Context> m_to;
int m_calls;
};
protocol::Response toProtocolValue(v8::Local<v8::Context> context,
v8::Local<v8::Value> value, int maxDepth,
std::unique_ptr<protocol::Value>* result) {
......@@ -164,17 +99,6 @@ protocol::Response toProtocolValue(v8::Local<v8::Context> context,
} // namespace
v8::MaybeLocal<v8::Value> copyValueFromDebuggerContext(
v8::Isolate* isolate, v8::Local<v8::Context> debuggerContext,
v8::Local<v8::Context> toContext, v8::Local<v8::Value> value) {
V8ValueCopier copier;
copier.m_isolate = isolate;
copier.m_from = debuggerContext;
copier.m_to = toContext;
copier.m_calls = 0;
return copier.copy(value, 0);
}
v8::Maybe<bool> createDataProperty(v8::Local<v8::Context> context,
v8::Local<v8::Object> object,
v8::Local<v8::Name> key,
......
......@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_INSPECTOR_V8VALUECOPIER_H_
#define V8_INSPECTOR_V8VALUECOPIER_H_
#ifndef V8_INSPECTOR_V8VALUEUTILS_H_
#define V8_INSPECTOR_V8VALUEUTILS_H_
#include "src/inspector/protocol/Protocol.h"
......@@ -11,9 +11,6 @@
namespace v8_inspector {
v8::MaybeLocal<v8::Value> copyValueFromDebuggerContext(
v8::Isolate*, v8::Local<v8::Context> debuggerContext,
v8::Local<v8::Context> toContext, v8::Local<v8::Value>);
v8::Maybe<bool> createDataProperty(v8::Local<v8::Context>,
v8::Local<v8::Object>,
v8::Local<v8::Name> key,
......@@ -26,4 +23,4 @@ protocol::Response toProtocolValue(v8::Local<v8::Context>, v8::Local<v8::Value>,
} // namespace v8_inspector
#endif // V8_INSPECTOR_V8VALUECOPIER_H_
#endif // V8_INSPECTOR_V8VALUEUTILS_H_
......@@ -69,6 +69,7 @@ int PropertyDetails::field_width_in_words() const {
return representation().IsDouble() ? kDoubleSize / kPointerSize : 1;
}
TYPE_CHECKER(BreakPoint, TUPLE2_TYPE)
TYPE_CHECKER(BreakPointInfo, TUPLE2_TYPE)
TYPE_CHECKER(ByteArray, BYTE_ARRAY_TYPE)
TYPE_CHECKER(BytecodeArray, BYTECODE_ARRAY_TYPE)
......
......@@ -151,6 +151,7 @@
// - ObjectTemplateInfo
// - Script
// - DebugInfo
// - BreakPoint
// - BreakPointInfo
// - StackFrameInfo
// - SourcePositionTableWithFrameCache
......@@ -1004,6 +1005,7 @@ template <class C> inline bool Is(Object* obj);
V(ArrayList) \
V(BoilerplateDescription) \
V(Boolean) \
V(BreakPoint) \
V(BreakPointInfo) \
V(ByteArray) \
V(BytecodeArray) \
......
......@@ -18,6 +18,7 @@ namespace internal {
CAST_ACCESSOR(BreakPointInfo)
CAST_ACCESSOR(DebugInfo)
CAST_ACCESSOR(CoverageInfo)
CAST_ACCESSOR(BreakPoint)
SMI_ACCESSORS(DebugInfo, flags, kFlagsOffset)
ACCESSORS(DebugInfo, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
......@@ -29,6 +30,9 @@ ACCESSORS(DebugInfo, coverage_info, Object, kCoverageInfoOffset)
SMI_ACCESSORS(BreakPointInfo, source_position, kSourcePositionOffset)
ACCESSORS(BreakPointInfo, break_point_objects, Object, kBreakPointObjectsOffset)
SMI_ACCESSORS(BreakPoint, id, kIdOffset)
ACCESSORS(BreakPoint, condition, String, kConditionOffset)
bool DebugInfo::HasDebugBytecodeArray() {
return debug_bytecode_array()->IsBytecodeArray();
}
......
......@@ -187,6 +187,18 @@ bool DebugInfo::ClearCoverageInfo() {
return flags() == kNone;
}
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();
}
} // namespace
// Remove the specified break point object.
void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
Handle<Object> break_point_object) {
......@@ -195,7 +207,7 @@ void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
if (break_point_info->break_point_objects()->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 (break_point_info->break_point_objects() == *break_point_object) {
if (IsEqual(break_point_info->break_point_objects(), *break_point_object)) {
break_point_info->set_break_point_objects(
isolate->heap()->undefined_value());
}
......@@ -209,7 +221,7 @@ void BreakPointInfo::ClearBreakPoint(Handle<BreakPointInfo> break_point_info,
isolate->factory()->NewFixedArray(old_array->length() - 1);
int found_count = 0;
for (int i = 0; i < old_array->length(); i++) {
if (old_array->get(i) == *break_point_object) {
if (IsEqual(old_array->get(i), *break_point_object)) {
DCHECK(found_count == 0);
found_count++;
} else {
......@@ -247,7 +259,7 @@ void BreakPointInfo::SetBreakPoint(Handle<BreakPointInfo> break_point_info,
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 (old_array->get(i) == *break_point_object) return;
if (IsEqual(old_array->get(i), *break_point_object)) return;
new_array->set(i, old_array->get(i));
}
// Add the new break point.
......@@ -265,12 +277,13 @@ bool BreakPointInfo::HasBreakPointObject(
}
// Single break point.
if (!break_point_info->break_point_objects()->IsFixedArray()) {
return break_point_info->break_point_objects() == *break_point_object;
return IsEqual(break_point_info->break_point_objects(),
*break_point_object);
}
// Multiple break points.
FixedArray* array = FixedArray::cast(break_point_info->break_point_objects());
for (int i = 0; i < array->length(); i++) {
if (array->get(i) == *break_point_object) {
if (IsEqual(array->get(i), *break_point_object)) {
return true;
}
}
......
......@@ -185,6 +185,21 @@ class CoverageInfo : public FixedArray {
DISALLOW_IMPLICIT_CONSTRUCTORS(CoverageInfo);
};
// Holds breakpoint related information. This object is used by inspector.
class BreakPoint : public Tuple2 {
public:
DECL_INT_ACCESSORS(id)
DECL_ACCESSORS(condition, String)
DECL_CAST(BreakPoint)
static const int kIdOffset = kValue1Offset;
static const int kConditionOffset = kValue2Offset;
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(BreakPoint);
};
} // namespace internal
} // namespace v8
......
......@@ -526,7 +526,6 @@
'v8_libsampler',
'inspector/inspector.gyp:protocol_generated_sources#target',
'inspector/inspector.gyp:inspector_injected_script#target',
'inspector/inspector.gyp:inspector_debugger_script#target',
],
'objs': ['foo.o'],
'variables': {
......
......@@ -337,9 +337,7 @@ class InterpreterHandle {
// We hit one or several breakpoints. Clear stepping, notify the
// listeners and return.
ClearStepping();
Handle<Object> hit_breakpoints_js =
isolate_->factory()->NewJSArrayWithElements(breakpoints);
isolate_->debug()->OnDebugBreak(hit_breakpoints_js);
isolate_->debug()->OnDebugBreak(breakpoints);
return;
}
}
......@@ -364,7 +362,7 @@ class InterpreterHandle {
}
if (!hit_step) return;
ClearStepping();
isolate_->debug()->OnDebugBreak(isolate_->factory()->undefined_value());
isolate_->debug()->OnDebugBreak(isolate_->factory()->empty_fixed_array());
}
int GetTopPosition(Handle<WasmCompiledModule> compiled_module) {
......
......@@ -2971,7 +2971,8 @@ 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) override {
v8::Local<v8::Value> break_points_hit,
const std::vector<int>&) override {
debug_break_count++;
}
int debug_break_count = 0;
......
......@@ -90,7 +90,8 @@ 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) override {
v8::Local<v8::Value> break_points_hit,
const std::vector<int>&) override {
printf("Break #%d\n", count_);
CHECK_GT(expected_breaks_.size(), count_);
......@@ -214,7 +215,8 @@ 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) override {
v8::Local<v8::Value> break_points_hit,
const std::vector<int>&) override {
printf("Break #%d\n", count_);
CHECK_GT(expected_values_.size(), count_);
auto& expected = expected_values_[count_];
......
......@@ -80,7 +80,7 @@ assertTrue(extension_count == 2 || extension_count == 3);
// This script, test-api.js and mjsunit.js has been loaded. If using d8, d8
// loads a normal script during startup too.
assertTrue(normal_count == 3 || normal_count == 4);
assertTrue(inspector_count == 1);
assertTrue(inspector_count == 0);
// Test a builtins script.
var array_script = Debug.findScript('native array.js');
......
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