Commit 839f55f5 authored by Yang Guo's avatar Yang Guo Committed by Commit Bot

[inspector] expose breakpoints for builtins and API functions.

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

Bug: v8:178
Cq-Include-Trybots: luci.chromium.try:linux_chromium_rel_ng;master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Idee461c6ff6c8a14b01229ea6448e437f3db6dab
Reviewed-on: https://chromium-review.googlesource.com/973202
Commit-Queue: Yang Guo <yangguo@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarAleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#52151}
parent 28190980
...@@ -9448,8 +9448,8 @@ bool debug::Script::SetBreakpoint(v8::Local<v8::String> condition, ...@@ -9448,8 +9448,8 @@ bool debug::Script::SetBreakpoint(v8::Local<v8::String> condition,
i::Handle<i::Script> script = Utils::OpenHandle(this); i::Handle<i::Script> script = Utils::OpenHandle(this);
i::Isolate* isolate = script->GetIsolate(); i::Isolate* isolate = script->GetIsolate();
int offset = GetSourceOffset(*location); int offset = GetSourceOffset(*location);
if (!isolate->debug()->SetBreakpoint(script, Utils::OpenHandle(*condition), if (!isolate->debug()->SetBreakPointForScript(
&offset, id)) { script, Utils::OpenHandle(*condition), &offset, id)) {
return false; return false;
} }
*location = GetSourceLocation(offset); *location = GetSourceLocation(offset);
...@@ -9858,6 +9858,35 @@ int64_t debug::GetNextRandomInt64(v8::Isolate* v8_isolate) { ...@@ -9858,6 +9858,35 @@ int64_t debug::GetNextRandomInt64(v8::Isolate* v8_isolate) {
->NextInt64(); ->NextInt64();
} }
int debug::GetDebuggingId(v8::Local<v8::Function> function) {
i::JSReceiver* callable = *v8::Utils::OpenHandle(*function);
if (!callable->IsJSFunction()) return i::SharedFunctionInfo::kNoDebuggingId;
i::JSFunction* fun = i::JSFunction::cast(callable);
i::SharedFunctionInfo* shared = fun->shared();
int id = shared->debugging_id();
if (id == i::SharedFunctionInfo::kNoDebuggingId) {
id = shared->GetHeap()->NextDebuggingId();
shared->set_debugging_id(id);
}
DCHECK_NE(i::SharedFunctionInfo::kNoDebuggingId, id);
return id;
}
bool debug::SetFunctionBreakpoint(v8::Local<v8::Function> function,
v8::Local<v8::String> condition,
BreakpointId* id) {
i::Handle<i::JSReceiver> callable = Utils::OpenHandle(*function);
if (!callable->IsJSFunction()) return false;
i::Handle<i::JSFunction> jsfunction =
i::Handle<i::JSFunction>::cast(callable);
i::Isolate* isolate = jsfunction->GetIsolate();
i::Handle<i::String> condition_string =
condition.IsEmpty() ? isolate->factory()->empty_string()
: Utils::OpenHandle(*condition);
return isolate->debug()->SetBreakpointForFunction(jsfunction,
condition_string, id);
}
Local<String> CpuProfileNode::GetFunctionName() const { Local<String> CpuProfileNode::GetFunctionName() const {
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this); const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
i::Isolate* isolate = node->isolate(); i::Isolate* isolate = node->isolate();
......
...@@ -506,6 +506,11 @@ v8::MaybeLocal<v8::Value> EvaluateGlobal(v8::Isolate* isolate, ...@@ -506,6 +506,11 @@ v8::MaybeLocal<v8::Value> EvaluateGlobal(v8::Isolate* isolate,
v8::Local<v8::String> source, v8::Local<v8::String> source,
bool throw_on_side_effect); bool throw_on_side_effect);
int GetDebuggingId(v8::Local<v8::Function> function);
bool SetFunctionBreakpoint(v8::Local<v8::Function> function,
v8::Local<v8::String> condition, BreakpointId* id);
} // namespace debug } // namespace debug
} // namespace v8 } // namespace v8
......
...@@ -607,7 +607,7 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function, ...@@ -607,7 +607,7 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
// Make sure the function is compiled and has set up the debug info. // Make sure the function is compiled and has set up the debug info.
Handle<SharedFunctionInfo> shared(function->shared()); Handle<SharedFunctionInfo> shared(function->shared());
if (!EnsureBreakInfo(shared)) return true; if (!EnsureBreakInfo(shared)) return false;
PrepareFunctionForBreakPoints(shared); PrepareFunctionForBreakPoints(shared);
Handle<DebugInfo> debug_info(shared->GetDebugInfo()); Handle<DebugInfo> debug_info(shared->GetDebugInfo());
// Source positions starts with zero. // Source positions starts with zero.
...@@ -627,8 +627,11 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function, ...@@ -627,8 +627,11 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
} }
bool Debug::SetBreakPointForScript(Handle<Script> script, bool Debug::SetBreakPointForScript(Handle<Script> script,
Handle<BreakPoint> break_point, Handle<String> condition,
int* source_position) { int* source_position, int* id) {
*id = ++thread_local_.last_breakpoint_id_;
Handle<BreakPoint> break_point =
isolate_->factory()->NewBreakPoint(*id, condition);
if (script->type() == Script::TYPE_WASM) { if (script->type() == Script::TYPE_WASM) {
Handle<WasmCompiledModule> compiled_module( Handle<WasmCompiledModule> compiled_module(
WasmCompiledModule::cast(script->wasm_compiled_module()), isolate_); WasmCompiledModule::cast(script->wasm_compiled_module()), isolate_);
...@@ -741,12 +744,13 @@ void Debug::ClearBreakPoint(Handle<BreakPoint> break_point) { ...@@ -741,12 +744,13 @@ void Debug::ClearBreakPoint(Handle<BreakPoint> break_point) {
} }
} }
bool Debug::SetBreakpoint(Handle<Script> script, Handle<String> condition, bool Debug::SetBreakpointForFunction(Handle<JSFunction> function,
int* offset, int* id) { Handle<String> condition, int* id) {
*id = ++thread_local_.last_breakpoint_id_; *id = ++thread_local_.last_breakpoint_id_;
Handle<BreakPoint> breakpoint = Handle<BreakPoint> breakpoint =
isolate_->factory()->NewBreakPoint(*id, condition); isolate_->factory()->NewBreakPoint(*id, condition);
return SetBreakPointForScript(script, breakpoint, offset); int source_position = 0;
return SetBreakPoint(function, breakpoint, &source_position);
} }
void Debug::RemoveBreakpoint(int id) { void Debug::RemoveBreakpoint(int id) {
......
...@@ -242,15 +242,14 @@ class Debug { ...@@ -242,15 +242,14 @@ class Debug {
// Break point handling. // Break point handling.
bool SetBreakPoint(Handle<JSFunction> function, bool SetBreakPoint(Handle<JSFunction> function,
Handle<BreakPoint> break_point, int* source_position); Handle<BreakPoint> break_point, int* source_position);
bool SetBreakPointForScript(Handle<Script> script,
Handle<BreakPoint> break_point,
int* source_position);
void ClearBreakPoint(Handle<BreakPoint> break_point); void ClearBreakPoint(Handle<BreakPoint> break_point);
void ChangeBreakOnException(ExceptionBreakType type, bool enable); void ChangeBreakOnException(ExceptionBreakType type, bool enable);
bool IsBreakOnException(ExceptionBreakType type); bool IsBreakOnException(ExceptionBreakType type);
bool SetBreakpoint(Handle<Script> script, Handle<String> condition, bool SetBreakPointForScript(Handle<Script> script, Handle<String> condition,
int* offset, int* id); int* source_position, int* id);
bool SetBreakpointForFunction(Handle<JSFunction> function,
Handle<String> condition, int* id);
void RemoveBreakpoint(int id); void RemoveBreakpoint(int id);
// Find breakpoints from the debug info and the break location and check // Find breakpoints from the debug info and the break location and check
......
...@@ -2641,6 +2641,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo( ...@@ -2641,6 +2641,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
FixedArrayOfWeakCells::Add(noscript_shared_function_infos(), share); FixedArrayOfWeakCells::Add(noscript_shared_function_infos(), share);
isolate()->heap()->set_noscript_shared_function_infos(*new_noscript_list); isolate()->heap()->set_noscript_shared_function_infos(*new_noscript_list);
DCHECK_EQ(SharedFunctionInfo::kNoDebuggingId, share->debugging_id());
#ifdef VERIFY_HEAP #ifdef VERIFY_HEAP
share->SharedFunctionInfoVerify(); share->SharedFunctionInfoVerify();
#endif #endif
......
...@@ -668,15 +668,22 @@ uint32_t Heap::HashSeed() { ...@@ -668,15 +668,22 @@ uint32_t Heap::HashSeed() {
int Heap::NextScriptId() { int Heap::NextScriptId() {
int last_id = last_script_id()->value(); int last_id = last_script_id()->value();
if (last_id == Smi::kMaxValue) { if (last_id == Smi::kMaxValue) last_id = v8::UnboundScript::kNoScriptId;
last_id = 1;
} else {
last_id++; last_id++;
}
set_last_script_id(Smi::FromInt(last_id)); set_last_script_id(Smi::FromInt(last_id));
return last_id; return last_id;
} }
int Heap::NextDebuggingId() {
int last_id = last_debugging_id()->value();
if (last_id == SharedFunctionInfo::DebuggingIdBits::kMax) {
last_id = SharedFunctionInfo::kNoDebuggingId;
}
last_id++;
set_last_debugging_id(Smi::FromInt(last_id));
return last_id;
}
int Heap::GetNextTemplateSerialNumber() { int Heap::GetNextTemplateSerialNumber() {
int next_serial_number = next_template_serial_number()->value() + 1; int next_serial_number = next_template_serial_number()->value() + 1;
set_next_template_serial_number(Smi::FromInt(next_serial_number)); set_next_template_serial_number(Smi::FromInt(next_serial_number));
......
...@@ -279,6 +279,7 @@ using v8::MemoryPressureLevel; ...@@ -279,6 +279,7 @@ using v8::MemoryPressureLevel;
V(Smi, stack_limit, StackLimit) \ V(Smi, stack_limit, StackLimit) \
V(Smi, real_stack_limit, RealStackLimit) \ V(Smi, real_stack_limit, RealStackLimit) \
V(Smi, last_script_id, LastScriptId) \ V(Smi, last_script_id, LastScriptId) \
V(Smi, last_debugging_id, LastDebuggingId) \
V(Smi, hash_seed, HashSeed) \ V(Smi, hash_seed, HashSeed) \
/* To distinguish the function templates, so that we can find them in the */ \ /* To distinguish the function templates, so that we can find them in the */ \
/* function cache of the native context. */ \ /* function cache of the native context. */ \
...@@ -890,6 +891,7 @@ class Heap { ...@@ -890,6 +891,7 @@ class Heap {
inline uint32_t HashSeed(); inline uint32_t HashSeed();
inline int NextScriptId(); inline int NextScriptId();
inline int NextDebuggingId();
inline int GetNextTemplateSerialNumber(); inline int GetNextTemplateSerialNumber();
void SetSerializedObjects(FixedArray* objects); void SetSerializedObjects(FixedArray* objects);
......
...@@ -606,6 +606,7 @@ void Heap::CreateInitialObjects() { ...@@ -606,6 +606,7 @@ void Heap::CreateInitialObjects() {
// Handling of script id generation is in Heap::NextScriptId(). // Handling of script id generation is in Heap::NextScriptId().
set_last_script_id(Smi::FromInt(v8::UnboundScript::kNoScriptId)); set_last_script_id(Smi::FromInt(v8::UnboundScript::kNoScriptId));
set_last_debugging_id(Smi::FromInt(SharedFunctionInfo::kNoDebuggingId));
set_next_template_serial_number(Smi::kZero); set_next_template_serial_number(Smi::kZero);
// Allocate the empty OrderedHashMap. // Allocate the empty OrderedHashMap.
......
...@@ -484,23 +484,15 @@ void V8Console::valuesCallback(const v8::FunctionCallbackInfo<v8::Value>& info, ...@@ -484,23 +484,15 @@ void V8Console::valuesCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
static void setFunctionBreakpoint(ConsoleHelper& helper, int sessionId, static void setFunctionBreakpoint(ConsoleHelper& helper, int sessionId,
v8::Local<v8::Function> function, v8::Local<v8::Function> function,
V8DebuggerAgentImpl::BreakpointSource source, V8DebuggerAgentImpl::BreakpointSource source,
const String16& condition, bool enable) { v8::Local<v8::String> condition,
String16 scriptId = String16::fromInteger(function->ScriptId()); bool enable) {
int lineNumber = function->GetScriptLineNumber(); V8InspectorSessionImpl* session = helper.session(sessionId);
int columnNumber = function->GetScriptColumnNumber(); if (session == nullptr) return;
if (lineNumber == v8::Function::kLineOffsetNotFound ||
columnNumber == v8::Function::kLineOffsetNotFound)
return;
if (V8InspectorSessionImpl* session = helper.session(sessionId)) {
if (!session->debuggerAgent()->enabled()) return; if (!session->debuggerAgent()->enabled()) return;
if (enable) { if (enable) {
session->debuggerAgent()->setBreakpointAt( session->debuggerAgent()->setBreakpointFor(function, condition, source);
scriptId, lineNumber, columnNumber, source, condition);
} else { } else {
session->debuggerAgent()->removeBreakpointAt(scriptId, lineNumber, session->debuggerAgent()->removeBreakpointFor(function, source);
columnNumber, source);
}
} }
} }
...@@ -509,10 +501,14 @@ void V8Console::debugFunctionCallback( ...@@ -509,10 +501,14 @@ void V8Console::debugFunctionCallback(
v8::debug::ConsoleCallArguments args(info); v8::debug::ConsoleCallArguments args(info);
ConsoleHelper helper(args, v8::debug::ConsoleContext(), m_inspector); ConsoleHelper helper(args, v8::debug::ConsoleContext(), m_inspector);
v8::Local<v8::Function> function; v8::Local<v8::Function> function;
v8::Local<v8::String> condition;
if (!helper.firstArgAsFunction().ToLocal(&function)) return; if (!helper.firstArgAsFunction().ToLocal(&function)) return;
if (args.Length() > 1 && args[1]->IsString()) {
condition = args[1].As<v8::String>();
}
setFunctionBreakpoint(helper, sessionId, function, setFunctionBreakpoint(helper, sessionId, function,
V8DebuggerAgentImpl::DebugCommandBreakpointSource, V8DebuggerAgentImpl::DebugCommandBreakpointSource,
String16(), true); condition, true);
} }
void V8Console::undebugFunctionCallback( void V8Console::undebugFunctionCallback(
...@@ -523,7 +519,7 @@ void V8Console::undebugFunctionCallback( ...@@ -523,7 +519,7 @@ void V8Console::undebugFunctionCallback(
if (!helper.firstArgAsFunction().ToLocal(&function)) return; if (!helper.firstArgAsFunction().ToLocal(&function)) return;
setFunctionBreakpoint(helper, sessionId, function, setFunctionBreakpoint(helper, sessionId, function,
V8DebuggerAgentImpl::DebugCommandBreakpointSource, V8DebuggerAgentImpl::DebugCommandBreakpointSource,
String16(), false); v8::Local<v8::String>(), false);
} }
void V8Console::monitorFunctionCallback( void V8Console::monitorFunctionCallback(
...@@ -547,7 +543,8 @@ void V8Console::monitorFunctionCallback( ...@@ -547,7 +543,8 @@ void V8Console::monitorFunctionCallback(
"Array.prototype.join.call(arguments, \", \") : \"\")) && false"); "Array.prototype.join.call(arguments, \", \") : \"\")) && false");
setFunctionBreakpoint(helper, sessionId, function, setFunctionBreakpoint(helper, sessionId, function,
V8DebuggerAgentImpl::MonitorCommandBreakpointSource, V8DebuggerAgentImpl::MonitorCommandBreakpointSource,
builder.toString(), true); toV8String(info.GetIsolate(), builder.toString()),
true);
} }
void V8Console::unmonitorFunctionCallback( void V8Console::unmonitorFunctionCallback(
...@@ -558,7 +555,7 @@ void V8Console::unmonitorFunctionCallback( ...@@ -558,7 +555,7 @@ void V8Console::unmonitorFunctionCallback(
if (!helper.firstArgAsFunction().ToLocal(&function)) return; if (!helper.firstArgAsFunction().ToLocal(&function)) return;
setFunctionBreakpoint(helper, sessionId, function, setFunctionBreakpoint(helper, sessionId, function,
V8DebuggerAgentImpl::MonitorCommandBreakpointSource, V8DebuggerAgentImpl::MonitorCommandBreakpointSource,
String16(), false); v8::Local<v8::String>(), false);
} }
void V8Console::lastEvaluationResultCallback( void V8Console::lastEvaluationResultCallback(
...@@ -711,7 +708,7 @@ v8::Local<v8::Object> V8Console::createCommandLineAPI( ...@@ -711,7 +708,7 @@ v8::Local<v8::Object> V8Console::createCommandLineAPI(
createBoundFunctionProperty( createBoundFunctionProperty(
context, commandLineAPI, data, "debug", context, commandLineAPI, data, "debug",
&V8Console::call<&V8Console::debugFunctionCallback>, &V8Console::call<&V8Console::debugFunctionCallback>,
"function debug(function) { [Command Line API] }"); "function debug(function, condition) { [Command Line API] }");
createBoundFunctionProperty( createBoundFunctionProperty(
context, commandLineAPI, data, "undebug", context, commandLineAPI, data, "undebug",
&V8Console::call<&V8Console::undebugFunctionCallback>, &V8Console::call<&V8Console::undebugFunctionCallback>,
......
...@@ -97,25 +97,38 @@ String16 generateBreakpointId(BreakpointType type, ...@@ -97,25 +97,38 @@ String16 generateBreakpointId(BreakpointType type,
return builder.toString(); return builder.toString();
} }
String16 generateBreakpointId(BreakpointType type,
v8::Local<v8::Function> function) {
String16Builder builder;
builder.appendNumber(static_cast<int>(type));
builder.append(':');
builder.appendNumber(v8::debug::GetDebuggingId(function));
return builder.toString();
}
bool parseBreakpointId(const String16& breakpointId, BreakpointType* type, bool parseBreakpointId(const String16& breakpointId, BreakpointType* type,
String16* scriptSelector = nullptr, String16* scriptSelector = nullptr,
int* lineNumber = nullptr, int* columnNumber = nullptr) { int* lineNumber = nullptr, int* columnNumber = nullptr) {
size_t typeLineSeparator = breakpointId.find(':'); size_t typeLineSeparator = breakpointId.find(':');
if (typeLineSeparator == String16::kNotFound) return false; if (typeLineSeparator == String16::kNotFound) return false;
size_t lineColumnSeparator = breakpointId.find(':', typeLineSeparator + 1);
if (lineColumnSeparator == String16::kNotFound) return false;
size_t columnSelectorSeparator =
breakpointId.find(':', lineColumnSeparator + 1);
if (columnSelectorSeparator == String16::kNotFound) return false;
if (type) {
int rawType = breakpointId.substring(0, typeLineSeparator).toInteger(); int rawType = breakpointId.substring(0, typeLineSeparator).toInteger();
if (rawType < static_cast<int>(BreakpointType::kByUrl) || if (rawType < static_cast<int>(BreakpointType::kByUrl) ||
rawType > static_cast<int>(BreakpointType::kMonitorCommand)) { rawType > static_cast<int>(BreakpointType::kMonitorCommand)) {
return false; return false;
} }
*type = static_cast<BreakpointType>(rawType); if (type) *type = static_cast<BreakpointType>(rawType);
if (rawType == static_cast<int>(BreakpointType::kDebugCommand) ||
rawType == static_cast<int>(BreakpointType::kMonitorCommand)) {
// The script and source position is not encoded in this case.
return true;
} }
size_t lineColumnSeparator = breakpointId.find(':', typeLineSeparator + 1);
if (lineColumnSeparator == String16::kNotFound) return false;
size_t columnSelectorSeparator =
breakpointId.find(':', lineColumnSeparator + 1);
if (columnSelectorSeparator == String16::kNotFound) return false;
if (scriptSelector) { if (scriptSelector) {
*scriptSelector = breakpointId.substring(columnSelectorSeparator + 1); *scriptSelector = breakpointId.substring(columnSelectorSeparator + 1);
} }
...@@ -822,6 +835,19 @@ V8DebuggerAgentImpl::setBreakpointImpl(const String16& breakpointId, ...@@ -822,6 +835,19 @@ V8DebuggerAgentImpl::setBreakpointImpl(const String16& breakpointId,
.build(); .build();
} }
void V8DebuggerAgentImpl::setBreakpointImpl(const String16& breakpointId,
v8::Local<v8::Function> function,
v8::Local<v8::String> condition) {
v8::debug::BreakpointId debuggerBreakpointId;
if (!v8::debug::SetFunctionBreakpoint(function, condition,
&debuggerBreakpointId)) {
return;
}
m_debuggerBreakpointIdToBreakpointId[debuggerBreakpointId] = breakpointId;
m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back(
debuggerBreakpointId);
}
Response V8DebuggerAgentImpl::searchInContent( Response V8DebuggerAgentImpl::searchInContent(
const String16& scriptId, const String16& query, const String16& scriptId, const String16& query,
Maybe<bool> optionalCaseSensitive, Maybe<bool> optionalIsRegex, Maybe<bool> optionalCaseSensitive, Maybe<bool> optionalIsRegex,
...@@ -1604,29 +1630,26 @@ void V8DebuggerAgentImpl::breakProgram( ...@@ -1604,29 +1630,26 @@ void V8DebuggerAgentImpl::breakProgram(
} }
} }
void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId, void V8DebuggerAgentImpl::setBreakpointFor(v8::Local<v8::Function> function,
int lineNumber, int columnNumber, v8::Local<v8::String> condition,
BreakpointSource source, BreakpointSource source) {
const String16& condition) {
String16 breakpointId = generateBreakpointId( String16 breakpointId = generateBreakpointId(
source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand
: BreakpointType::kMonitorCommand, : BreakpointType::kMonitorCommand,
scriptId, lineNumber, columnNumber); function);
if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) != if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
m_breakpointIdToDebuggerBreakpointIds.end()) { m_breakpointIdToDebuggerBreakpointIds.end()) {
return; return;
} }
setBreakpointImpl(breakpointId, scriptId, condition, lineNumber, setBreakpointImpl(breakpointId, function, condition);
columnNumber);
} }
void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, void V8DebuggerAgentImpl::removeBreakpointFor(v8::Local<v8::Function> function,
int lineNumber, int columnNumber,
BreakpointSource source) { BreakpointSource source) {
String16 breakpointId = generateBreakpointId( String16 breakpointId = generateBreakpointId(
source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand
: BreakpointType::kMonitorCommand, : BreakpointType::kMonitorCommand,
scriptId, lineNumber, columnNumber); function);
removeBreakpointImpl(breakpointId); removeBreakpointImpl(breakpointId);
} }
......
...@@ -120,11 +120,11 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { ...@@ -120,11 +120,11 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
bool enabled() const { return m_enabled; } bool enabled() const { return m_enabled; }
void setBreakpointAt(const String16& scriptId, int lineNumber, void setBreakpointFor(v8::Local<v8::Function> function,
int columnNumber, BreakpointSource, v8::Local<v8::String> condition,
const String16& condition = String16()); BreakpointSource source);
void removeBreakpointAt(const String16& scriptId, int lineNumber, void removeBreakpointFor(v8::Local<v8::Function> function,
int columnNumber, BreakpointSource); BreakpointSource source);
void schedulePauseOnNextStatement( void schedulePauseOnNextStatement(
const String16& breakReason, const String16& breakReason,
std::unique_ptr<protocol::DictionaryValue> data); std::unique_ptr<protocol::DictionaryValue> data);
...@@ -164,6 +164,9 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend { ...@@ -164,6 +164,9 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
std::unique_ptr<protocol::Debugger::Location> setBreakpointImpl( std::unique_ptr<protocol::Debugger::Location> setBreakpointImpl(
const String16& breakpointId, const String16& scriptId, const String16& breakpointId, const String16& scriptId,
const String16& condition, int lineNumber, int columnNumber); const String16& condition, int lineNumber, int columnNumber);
void setBreakpointImpl(const String16& breakpointId,
v8::Local<v8::Function> function,
v8::Local<v8::String> condition);
void removeBreakpointImpl(const String16& breakpointId); void removeBreakpointImpl(const String16& breakpointId);
void clearBreakDetails(); void clearBreakDetails();
......
...@@ -209,6 +209,8 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, debugger_hints, ...@@ -209,6 +209,8 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, debugger_hints,
BIT_FIELD_ACCESSORS(SharedFunctionInfo, debugger_hints, BIT_FIELD_ACCESSORS(SharedFunctionInfo, debugger_hints,
has_reported_binary_coverage, has_reported_binary_coverage,
SharedFunctionInfo::HasReportedBinaryCoverageBit) SharedFunctionInfo::HasReportedBinaryCoverageBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, debugger_hints, debugging_id,
SharedFunctionInfo::DebuggingIdBits)
void SharedFunctionInfo::DontAdaptArguments() { void SharedFunctionInfo::DontAdaptArguments() {
DCHECK(code()->kind() == Code::BUILTIN || code()->kind() == Code::STUB); DCHECK(code()->kind() == Code::BUILTIN || code()->kind() == Code::STUB);
......
...@@ -246,6 +246,11 @@ class SharedFunctionInfo : public HeapObject { ...@@ -246,6 +246,11 @@ class SharedFunctionInfo : public HeapObject {
// Indicates that the function has been reported for binary code coverage. // Indicates that the function has been reported for binary code coverage.
DECL_BOOLEAN_ACCESSORS(has_reported_binary_coverage) DECL_BOOLEAN_ACCESSORS(has_reported_binary_coverage)
// Id assigned to the function for debugging.
// This could also be implemented as a weak hash table.
inline int debugging_id() const;
inline void set_debugging_id(int value);
// The function's name if it is non-empty, otherwise the inferred name. // The function's name if it is non-empty, otherwise the inferred name.
String* DebugName(); String* DebugName();
...@@ -508,11 +513,14 @@ class SharedFunctionInfo : public HeapObject { ...@@ -508,11 +513,14 @@ class SharedFunctionInfo : public HeapObject {
V(ComputedHasNoSideEffectBit, bool, 1, _) \ V(ComputedHasNoSideEffectBit, bool, 1, _) \
V(DebugIsBlackboxedBit, bool, 1, _) \ V(DebugIsBlackboxedBit, bool, 1, _) \
V(ComputedDebugIsBlackboxedBit, bool, 1, _) \ V(ComputedDebugIsBlackboxedBit, bool, 1, _) \
V(HasReportedBinaryCoverageBit, bool, 1, _) V(HasReportedBinaryCoverageBit, bool, 1, _) \
V(DebuggingIdBits, int, 20, _)
DEFINE_BIT_FIELDS(DEBUGGER_HINTS_BIT_FIELDS) DEFINE_BIT_FIELDS(DEBUGGER_HINTS_BIT_FIELDS)
#undef DEBUGGER_HINTS_BIT_FIELDS #undef DEBUGGER_HINTS_BIT_FIELDS
static const int kNoDebuggingId = 0;
// Indicates that this function uses a super property (or an eval that may // Indicates that this function uses a super property (or an eval that may
// use a super property). // use a super property).
// This is needed to set up the [[HomeObject]] on the function instance. // This is needed to set up the [[HomeObject]] on the function instance.
......
...@@ -3237,12 +3237,12 @@ TEST(PauseInScript) { ...@@ -3237,12 +3237,12 @@ TEST(PauseInScript) {
.ToLocalChecked(); .ToLocalChecked();
// Set breakpoint in the script. // Set breakpoint in the script.
i::Handle<i::BreakPoint> break_point =
isolate->factory()->NewBreakPoint(0, isolate->factory()->empty_string());
int position = 0;
i::Handle<i::Script> i_script( i::Handle<i::Script> i_script(
i::Script::cast(v8::Utils::OpenHandle(*script)->shared()->script())); i::Script::cast(v8::Utils::OpenHandle(*script)->shared()->script()));
isolate->debug()->SetBreakPointForScript(i_script, break_point, &position); i::Handle<i::String> condition = isolate->factory()->empty_string();
int position = 0;
int id;
isolate->debug()->SetBreakPointForScript(i_script, condition, &position, &id);
break_point_hit_count = 0; break_point_hit_count = 0;
v8::Local<v8::Value> r = script->Run(context).ToLocalChecked(); v8::Local<v8::Value> r = script->Run(context).ToLocalChecked();
......
...@@ -235,7 +235,7 @@ Running test: testDebug ...@@ -235,7 +235,7 @@ Running test: testDebug
result : { result : {
result : { result : {
className : Function className : Function
description : function debug(function) { [Command Line API] } description : function debug(function, condition) { [Command Line API] }
objectId : <objectId> objectId : <objectId>
type : function type : function
} }
...@@ -255,13 +255,39 @@ Running test: testDebug ...@@ -255,13 +255,39 @@ Running test: testDebug
foo (:0:16) foo (:0:16)
(anonymous) (:0:0) (anonymous) (:0:0)
[ [
[0] : 5:0:12:<scriptId> [0] : 5:1
] ]
debugCommand
foo (:0:16) foo (:0:16)
(anonymous) (:0:0) (anonymous) (:0:0)
[ [
[0] : 5:0:12:<scriptId> [0] : 5:1
] ]
debugCommand
toUpper (:0:31)
(anonymous) (:0:0)
[
[0] : 5:2
]
debugCommand
callSetTimeout (:0:28)
(anonymous) (:0:0)
[
[0] : 5:3
]
debugCommand
callSetTimeout (:0:28)
(anonymous) (:0:0)
[
[0] : 5:3
]
debugCommand
fromCharCode (:0:40)
(anonymous) (:0:0)
[
[0] : 5:4
]
debugCommand
Running test: testMonitor Running test: testMonitor
{ {
...@@ -291,6 +317,7 @@ after first call ...@@ -291,6 +317,7 @@ after first call
store functions.. store functions..
function foo called function foo called
after first call after first call
function fromCharCode called with arguments: 1, 2, 3
Running test: testProfile Running test: testProfile
{ {
......
...@@ -81,6 +81,7 @@ InspectorTest.runAsyncTestSuite([ ...@@ -81,6 +81,7 @@ InspectorTest.runAsyncTestSuite([
let message = await Protocol.Debugger.oncePaused(); let message = await Protocol.Debugger.oncePaused();
session.logCallFrames(message.params.callFrames); session.logCallFrames(message.params.callFrames);
InspectorTest.logMessage(message.params.hitBreakpoints); InspectorTest.logMessage(message.params.hitBreakpoints);
InspectorTest.logMessage(message.params.reason);
await Protocol.Debugger.resume(); await Protocol.Debugger.resume();
await Protocol.Runtime.evaluate({expression: 'undebug(foo)', includeCommandLineAPI: true}); await Protocol.Runtime.evaluate({expression: 'undebug(foo)', includeCommandLineAPI: true});
await Protocol.Runtime.evaluate({ expression: 'foo()'}); await Protocol.Runtime.evaluate({ expression: 'foo()'});
...@@ -92,10 +93,59 @@ InspectorTest.runAsyncTestSuite([ ...@@ -92,10 +93,59 @@ InspectorTest.runAsyncTestSuite([
message = await Protocol.Debugger.oncePaused(); message = await Protocol.Debugger.oncePaused();
session.logCallFrames(message.params.callFrames); session.logCallFrames(message.params.callFrames);
InspectorTest.logMessage(message.params.hitBreakpoints); InspectorTest.logMessage(message.params.hitBreakpoints);
InspectorTest.logMessage(message.params.reason);
await Protocol.Debugger.resume(); await Protocol.Debugger.resume();
await Protocol.Runtime.evaluate({expression: 'this.undebug(foo)'}); await Protocol.Runtime.evaluate({expression: 'this.undebug(foo)'});
await Protocol.Runtime.evaluate({expression: 'foo()'}); await Protocol.Runtime.evaluate({expression: 'foo()'});
// Test builtin.
await Protocol.Runtime.evaluate({expression: 'function toUpper(x) { return x.toUpperCase() }'});
await Protocol.Runtime.evaluate({expression: 'debug(String.prototype.toUpperCase)', includeCommandLineAPI: true});
Protocol.Runtime.evaluate({ expression: 'toUpper("first call")'});
message = await Protocol.Debugger.oncePaused();
session.logCallFrames(message.params.callFrames);
InspectorTest.logMessage(message.params.hitBreakpoints);
InspectorTest.logMessage(message.params.reason);
await Protocol.Debugger.resume();
await Protocol.Runtime.evaluate({expression: 'undebug(String.prototype.toUpperCase)', includeCommandLineAPI: true});
await Protocol.Runtime.evaluate({ expression: 'toUpper("second call")'});
// Test API callback.
await Protocol.Runtime.evaluate({expression: 'function callSetTimeout() { setTimeout(function(){}, 0) }'});
await Protocol.Runtime.evaluate({expression: 'debug(setTimeout)', includeCommandLineAPI: true});
Protocol.Runtime.evaluate({ expression: 'callSetTimeout()'});
message = await Protocol.Debugger.oncePaused();
session.logCallFrames(message.params.callFrames);
InspectorTest.logMessage(message.params.hitBreakpoints);
InspectorTest.logMessage(message.params.reason);
let breakpointId = message.params.hitBreakpoints[0];
await Protocol.Debugger.resume();
await Protocol.Runtime.evaluate({expression: 'undebug(setTimeout)', includeCommandLineAPI: true});
await Protocol.Runtime.evaluate({ expression: 'callSetTimeout()'});
// Test remove break via protocol.
await Protocol.Runtime.evaluate({expression: 'function callSetTimeout() { setTimeout(function(){}, 0) }'});
await Protocol.Runtime.evaluate({expression: 'debug(setTimeout)', includeCommandLineAPI: true});
Protocol.Runtime.evaluate({ expression: 'callSetTimeout()'});
message = await Protocol.Debugger.oncePaused();
session.logCallFrames(message.params.callFrames);
InspectorTest.logMessage(message.params.hitBreakpoints);
InspectorTest.logMessage(message.params.reason);
await Protocol.Debugger.resume();
await Protocol.Debugger.removeBreakpoint({breakpointId});
await Protocol.Runtime.evaluate({ expression: 'callSetTimeout()'});
// Test condition.
await Protocol.Runtime.evaluate({expression: 'function fromCharCode(...args) { String.fromCharCode(...args) }'});
await Protocol.Runtime.evaluate({expression: 'debug(String.fromCharCode, "arguments.length == 3")'});
Protocol.Runtime.evaluate({ expression: 'fromCharCode("1", "2", "3")'});
message = await Protocol.Debugger.oncePaused();
session.logCallFrames(message.params.callFrames);
InspectorTest.logMessage(message.params.hitBreakpoints);
InspectorTest.logMessage(message.params.reason);
await Protocol.Runtime.evaluate({expression: 'undebug(String.fromCharCode)'});
await Protocol.Runtime.evaluate({ expression: 'fromCharCode()'});
await Protocol.Debugger.disable(); await Protocol.Debugger.disable();
}, },
...@@ -119,6 +169,13 @@ InspectorTest.runAsyncTestSuite([ ...@@ -119,6 +169,13 @@ InspectorTest.runAsyncTestSuite([
await Protocol.Runtime.evaluate({expression: 'this.unmonitor(foo)'}); await Protocol.Runtime.evaluate({expression: 'this.unmonitor(foo)'});
await Protocol.Runtime.evaluate({ expression: 'foo()'}); await Protocol.Runtime.evaluate({ expression: 'foo()'});
// Test builtin.
await Protocol.Runtime.evaluate({expression: 'function fromCharCode(...args) { String.fromCharCode(...args) }'});
await Protocol.Runtime.evaluate({expression: 'monitor(String.fromCharCode)'});
Protocol.Runtime.evaluate({ expression: 'fromCharCode("1", "2", "3")'});
await Protocol.Runtime.evaluate({expression: 'unmonitor(String.fromCharCode)'});
await Protocol.Runtime.evaluate({ expression: 'fromCharCode()'});
Protocol.Runtime.onConsoleAPICalled(null); Protocol.Runtime.onConsoleAPICalled(null);
await Protocol.Debugger.disable(); await Protocol.Debugger.disable();
await Protocol.Runtime.disable(); await Protocol.Runtime.disable();
......
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