首先,还想提下 console 这个对象(因为我们在这个模块上走了些弯路)。
正常来说 console 这个对象对于v8嵌入式来说没什么用,我们刚开始都认为V8不带这个对象,在 nodejs/chromium 中是外层注入的。后来才发现其实V8默认也会带这个对象,但仅当在 inspector 链接调试的时候才会起作用,它会通过 inspect 协议把 console 的内容发送到 CDT 中,然后你就可以像H5一样愉快的使用 console 了。PS:JavascriptCore 在 console 这个点上跟V8是一致的。
接下来说下这篇文章的主题,断点调试。 可能有的人会问,前面不是已经实现了inspect协议了吗?为什么还要自己实现调试呢?其实v8这里的处理是比较绕的,需要业务自己实现几个虚方法,最核心的是runMessageLoopOnPause和quitMessageLoopOnPause。
runMessageLoopOnPause,当CDT被触发断点时就会调用该方法,这时需要业务自己去加锁阻塞线程,并同时继续处理由CDT发送过来的消息,直到quitMessageLoopOnPause被触发,恢复线程,这样才能做到断点调试。
void V8InspectorClientImpl::runMessageLoopOnPause(int contextGroupId) {
std::shared_ptr<Engine> engine = V8ChannelImpl::runtime_->pEngine.lock();
if (engine) {
engine->jsRunner()->pauseThreadForInspector();
}
}
void V8InspectorClientImpl::quitMessageLoopOnPause() {
std::shared_ptr<Engine> engine = V8ChannelImpl::runtime_->pEngine.lock();
if (engine) {
engine->jsRunner()->resumeThreadForInspector();
}
}
void JavaScriptTaskRunner::pauseThreadForInspector() {
m_isInspectorCallPause = true;
while (m_isInspectorCallPause) {
std::shared_ptr<hippy::base::Task> task = GetNext();
if (task == nullptr) {
return;
}
if (task->canceled_ == false) {
task->Run();
}
}
}
void JavaScriptTaskRunner::resumeThreadForInspector() {
m_isInspectorCallPause = false;
}
std::shared_ptr<Task> TaskRunner::GetNext() {
std::unique_lock<std::mutex> lock(m_mutex);
for (;;) {
DelayedTimeInMs now = MonotonicallyIncreasingTime();
std::shared_ptr<Task> task = popTaskFromDelayedQueueNoLock(now);
while (task) {
postTaskNoLock(std::move(task));
task = popTaskFromDelayedQueueNoLock(now);
}
if (!task_queue_.empty()) {
std::shared_ptr<Task> result = std::move(task_queue_.front());
task_queue_.pop();
return result;
}
if (is_terminated_) {
m_cv.notify_all();
return nullptr;
}
if (task_queue_.empty() && !delayed_task_queue_.empty()) {
const DelayedEntry& delayed_task = delayed_task_queue_.top();
DelayedTimeInMs wait_in_msseconds = delayed_task.first - now;
bool notified =
m_cv.wait_for(lock, std::chrono::milliseconds(wait_in_msseconds)) ==
std::cv_status::timeout;
HIPPY_USE(notified);
} else {
m_cv.wait(lock);
}
}
}