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,
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)) {
if (!isolate->debug()->SetBreakPointForScript(
script, Utils::OpenHandle(*condition), &offset, id)) {
return false;
}
*location = GetSourceLocation(offset);
......@@ -9858,6 +9858,35 @@ int64_t debug::GetNextRandomInt64(v8::Isolate* v8_isolate) {
->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 {
const i::ProfileNode* node = reinterpret_cast<const i::ProfileNode*>(this);
i::Isolate* isolate = node->isolate();
......
......@@ -506,6 +506,11 @@ v8::MaybeLocal<v8::Value> EvaluateGlobal(v8::Isolate* isolate,
v8::Local<v8::String> source,
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 v8
......
......@@ -607,7 +607,7 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
// Make sure the function is compiled and has set up the debug info.
Handle<SharedFunctionInfo> shared(function->shared());
if (!EnsureBreakInfo(shared)) return true;
if (!EnsureBreakInfo(shared)) return false;
PrepareFunctionForBreakPoints(shared);
Handle<DebugInfo> debug_info(shared->GetDebugInfo());
// Source positions starts with zero.
......@@ -627,8 +627,11 @@ bool Debug::SetBreakPoint(Handle<JSFunction> function,
}
bool Debug::SetBreakPointForScript(Handle<Script> script,
Handle<BreakPoint> break_point,
int* source_position) {
Handle<String> condition,
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) {
Handle<WasmCompiledModule> compiled_module(
WasmCompiledModule::cast(script->wasm_compiled_module()), isolate_);
......@@ -741,12 +744,13 @@ void Debug::ClearBreakPoint(Handle<BreakPoint> break_point) {
}
}
bool Debug::SetBreakpoint(Handle<Script> script, Handle<String> condition,
int* offset, int* id) {
bool Debug::SetBreakpointForFunction(Handle<JSFunction> function,
Handle<String> condition, int* id) {
*id = ++thread_local_.last_breakpoint_id_;
Handle<BreakPoint> breakpoint =
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) {
......
......@@ -242,15 +242,14 @@ class Debug {
// Break point handling.
bool SetBreakPoint(Handle<JSFunction> function,
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 ChangeBreakOnException(ExceptionBreakType type, bool enable);
bool IsBreakOnException(ExceptionBreakType type);
bool SetBreakpoint(Handle<Script> script, Handle<String> condition,
int* offset, int* id);
bool SetBreakPointForScript(Handle<Script> script, Handle<String> condition,
int* source_position, int* id);
bool SetBreakpointForFunction(Handle<JSFunction> function,
Handle<String> condition, int* id);
void RemoveBreakpoint(int id);
// Find breakpoints from the debug info and the break location and check
......
......@@ -2641,6 +2641,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
FixedArrayOfWeakCells::Add(noscript_shared_function_infos(), share);
isolate()->heap()->set_noscript_shared_function_infos(*new_noscript_list);
DCHECK_EQ(SharedFunctionInfo::kNoDebuggingId, share->debugging_id());
#ifdef VERIFY_HEAP
share->SharedFunctionInfoVerify();
#endif
......
......@@ -668,15 +668,22 @@ uint32_t Heap::HashSeed() {
int Heap::NextScriptId() {
int last_id = last_script_id()->value();
if (last_id == Smi::kMaxValue) {
last_id = 1;
} else {
last_id++;
}
if (last_id == Smi::kMaxValue) last_id = v8::UnboundScript::kNoScriptId;
last_id++;
set_last_script_id(Smi::FromInt(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 next_serial_number = next_template_serial_number()->value() + 1;
set_next_template_serial_number(Smi::FromInt(next_serial_number));
......
......@@ -279,6 +279,7 @@ using v8::MemoryPressureLevel;
V(Smi, stack_limit, StackLimit) \
V(Smi, real_stack_limit, RealStackLimit) \
V(Smi, last_script_id, LastScriptId) \
V(Smi, last_debugging_id, LastDebuggingId) \
V(Smi, hash_seed, HashSeed) \
/* To distinguish the function templates, so that we can find them in the */ \
/* function cache of the native context. */ \
......@@ -890,6 +891,7 @@ class Heap {
inline uint32_t HashSeed();
inline int NextScriptId();
inline int NextDebuggingId();
inline int GetNextTemplateSerialNumber();
void SetSerializedObjects(FixedArray* objects);
......
......@@ -606,6 +606,7 @@ void Heap::CreateInitialObjects() {
// Handling of script id generation is in Heap::NextScriptId().
set_last_script_id(Smi::FromInt(v8::UnboundScript::kNoScriptId));
set_last_debugging_id(Smi::FromInt(SharedFunctionInfo::kNoDebuggingId));
set_next_template_serial_number(Smi::kZero);
// Allocate the empty OrderedHashMap.
......
......@@ -484,23 +484,15 @@ void V8Console::valuesCallback(const v8::FunctionCallbackInfo<v8::Value>& info,
static void setFunctionBreakpoint(ConsoleHelper& helper, int sessionId,
v8::Local<v8::Function> function,
V8DebuggerAgentImpl::BreakpointSource source,
const String16& condition, bool enable) {
String16 scriptId = String16::fromInteger(function->ScriptId());
int lineNumber = function->GetScriptLineNumber();
int columnNumber = function->GetScriptColumnNumber();
if (lineNumber == v8::Function::kLineOffsetNotFound ||
columnNumber == v8::Function::kLineOffsetNotFound)
return;
if (V8InspectorSessionImpl* session = helper.session(sessionId)) {
if (!session->debuggerAgent()->enabled()) return;
if (enable) {
session->debuggerAgent()->setBreakpointAt(
scriptId, lineNumber, columnNumber, source, condition);
} else {
session->debuggerAgent()->removeBreakpointAt(scriptId, lineNumber,
columnNumber, source);
}
v8::Local<v8::String> condition,
bool enable) {
V8InspectorSessionImpl* session = helper.session(sessionId);
if (session == nullptr) return;
if (!session->debuggerAgent()->enabled()) return;
if (enable) {
session->debuggerAgent()->setBreakpointFor(function, condition, source);
} else {
session->debuggerAgent()->removeBreakpointFor(function, source);
}
}
......@@ -509,10 +501,14 @@ void V8Console::debugFunctionCallback(
v8::debug::ConsoleCallArguments args(info);
ConsoleHelper helper(args, v8::debug::ConsoleContext(), m_inspector);
v8::Local<v8::Function> function;
v8::Local<v8::String> condition;
if (!helper.firstArgAsFunction().ToLocal(&function)) return;
if (args.Length() > 1 && args[1]->IsString()) {
condition = args[1].As<v8::String>();
}
setFunctionBreakpoint(helper, sessionId, function,
V8DebuggerAgentImpl::DebugCommandBreakpointSource,
String16(), true);
condition, true);
}
void V8Console::undebugFunctionCallback(
......@@ -523,7 +519,7 @@ void V8Console::undebugFunctionCallback(
if (!helper.firstArgAsFunction().ToLocal(&function)) return;
setFunctionBreakpoint(helper, sessionId, function,
V8DebuggerAgentImpl::DebugCommandBreakpointSource,
String16(), false);
v8::Local<v8::String>(), false);
}
void V8Console::monitorFunctionCallback(
......@@ -547,7 +543,8 @@ void V8Console::monitorFunctionCallback(
"Array.prototype.join.call(arguments, \", \") : \"\")) && false");
setFunctionBreakpoint(helper, sessionId, function,
V8DebuggerAgentImpl::MonitorCommandBreakpointSource,
builder.toString(), true);
toV8String(info.GetIsolate(), builder.toString()),
true);
}
void V8Console::unmonitorFunctionCallback(
......@@ -558,7 +555,7 @@ void V8Console::unmonitorFunctionCallback(
if (!helper.firstArgAsFunction().ToLocal(&function)) return;
setFunctionBreakpoint(helper, sessionId, function,
V8DebuggerAgentImpl::MonitorCommandBreakpointSource,
String16(), false);
v8::Local<v8::String>(), false);
}
void V8Console::lastEvaluationResultCallback(
......@@ -711,7 +708,7 @@ v8::Local<v8::Object> V8Console::createCommandLineAPI(
createBoundFunctionProperty(
context, commandLineAPI, data, "debug",
&V8Console::call<&V8Console::debugFunctionCallback>,
"function debug(function) { [Command Line API] }");
"function debug(function, condition) { [Command Line API] }");
createBoundFunctionProperty(
context, commandLineAPI, data, "undebug",
&V8Console::call<&V8Console::undebugFunctionCallback>,
......
......@@ -97,25 +97,38 @@ String16 generateBreakpointId(BreakpointType type,
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,
String16* scriptSelector = nullptr,
int* lineNumber = nullptr, int* columnNumber = nullptr) {
size_t typeLineSeparator = breakpointId.find(':');
if (typeLineSeparator == String16::kNotFound) return false;
int rawType = breakpointId.substring(0, typeLineSeparator).toInteger();
if (rawType < static_cast<int>(BreakpointType::kByUrl) ||
rawType > static_cast<int>(BreakpointType::kMonitorCommand)) {
return false;
}
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 (type) {
int rawType = breakpointId.substring(0, typeLineSeparator).toInteger();
if (rawType < static_cast<int>(BreakpointType::kByUrl) ||
rawType > static_cast<int>(BreakpointType::kMonitorCommand)) {
return false;
}
*type = static_cast<BreakpointType>(rawType);
}
if (scriptSelector) {
*scriptSelector = breakpointId.substring(columnSelectorSeparator + 1);
}
......@@ -822,6 +835,19 @@ V8DebuggerAgentImpl::setBreakpointImpl(const String16& breakpointId,
.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(
const String16& scriptId, const String16& query,
Maybe<bool> optionalCaseSensitive, Maybe<bool> optionalIsRegex,
......@@ -1604,29 +1630,26 @@ void V8DebuggerAgentImpl::breakProgram(
}
}
void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId,
int lineNumber, int columnNumber,
BreakpointSource source,
const String16& condition) {
void V8DebuggerAgentImpl::setBreakpointFor(v8::Local<v8::Function> function,
v8::Local<v8::String> condition,
BreakpointSource source) {
String16 breakpointId = generateBreakpointId(
source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand
: BreakpointType::kMonitorCommand,
scriptId, lineNumber, columnNumber);
function);
if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
m_breakpointIdToDebuggerBreakpointIds.end()) {
return;
}
setBreakpointImpl(breakpointId, scriptId, condition, lineNumber,
columnNumber);
setBreakpointImpl(breakpointId, function, condition);
}
void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId,
int lineNumber, int columnNumber,
BreakpointSource source) {
void V8DebuggerAgentImpl::removeBreakpointFor(v8::Local<v8::Function> function,
BreakpointSource source) {
String16 breakpointId = generateBreakpointId(
source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand
: BreakpointType::kMonitorCommand,
scriptId, lineNumber, columnNumber);
function);
removeBreakpointImpl(breakpointId);
}
......
......@@ -120,11 +120,11 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
bool enabled() const { return m_enabled; }
void setBreakpointAt(const String16& scriptId, int lineNumber,
int columnNumber, BreakpointSource,
const String16& condition = String16());
void removeBreakpointAt(const String16& scriptId, int lineNumber,
int columnNumber, BreakpointSource);
void setBreakpointFor(v8::Local<v8::Function> function,
v8::Local<v8::String> condition,
BreakpointSource source);
void removeBreakpointFor(v8::Local<v8::Function> function,
BreakpointSource source);
void schedulePauseOnNextStatement(
const String16& breakReason,
std::unique_ptr<protocol::DictionaryValue> data);
......@@ -164,6 +164,9 @@ class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
std::unique_ptr<protocol::Debugger::Location> setBreakpointImpl(
const String16& breakpointId, const String16& scriptId,
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 clearBreakDetails();
......
......@@ -209,6 +209,8 @@ BIT_FIELD_ACCESSORS(SharedFunctionInfo, debugger_hints,
BIT_FIELD_ACCESSORS(SharedFunctionInfo, debugger_hints,
has_reported_binary_coverage,
SharedFunctionInfo::HasReportedBinaryCoverageBit)
BIT_FIELD_ACCESSORS(SharedFunctionInfo, debugger_hints, debugging_id,
SharedFunctionInfo::DebuggingIdBits)
void SharedFunctionInfo::DontAdaptArguments() {
DCHECK(code()->kind() == Code::BUILTIN || code()->kind() == Code::STUB);
......
......@@ -246,6 +246,11 @@ class SharedFunctionInfo : public HeapObject {
// Indicates that the function has been reported for binary code 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.
String* DebugName();
......@@ -508,11 +513,14 @@ class SharedFunctionInfo : public HeapObject {
V(ComputedHasNoSideEffectBit, bool, 1, _) \
V(DebugIsBlackboxedBit, 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)
#undef DEBUGGER_HINTS_BIT_FIELDS
static const int kNoDebuggingId = 0;
// Indicates that this function uses a super property (or an eval that may
// use a super property).
// This is needed to set up the [[HomeObject]] on the function instance.
......
......@@ -3237,12 +3237,12 @@ TEST(PauseInScript) {
.ToLocalChecked();
// 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::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;
v8::Local<v8::Value> r = script->Run(context).ToLocalChecked();
......
......@@ -235,7 +235,7 @@ Running test: testDebug
result : {
result : {
className : Function
description : function debug(function) { [Command Line API] }
description : function debug(function, condition) { [Command Line API] }
objectId : <objectId>
type : function
}
......@@ -255,13 +255,39 @@ Running test: testDebug
foo (:0:16)
(anonymous) (:0:0)
[
[0] : 5:0:12:<scriptId>
[0] : 5:1
]
debugCommand
foo (:0:16)
(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
{
......@@ -291,6 +317,7 @@ after first call
store functions..
function foo called
after first call
function fromCharCode called with arguments: 1, 2, 3
Running test: testProfile
{
......
......@@ -81,6 +81,7 @@ InspectorTest.runAsyncTestSuite([
let 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(foo)', includeCommandLineAPI: true});
await Protocol.Runtime.evaluate({ expression: 'foo()'});
......@@ -92,10 +93,59 @@ InspectorTest.runAsyncTestSuite([
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: 'this.undebug(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();
},
......@@ -119,6 +169,13 @@ InspectorTest.runAsyncTestSuite([
await Protocol.Runtime.evaluate({expression: 'this.unmonitor(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);
await Protocol.Debugger.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