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

[inspector] support for cases when embedder doesn't call contextDestroyed

Node.js doesn't have good place to call contextDestroyed.
We need to cleanup everything on our side to allow clients to not call
contextDestroyed method.

R=dgozman@chromium.org,eostroukhov@chromium.com

Bug: none
Change-Id: Ibe3f01fd18afbfa579e5db66ab6f174d5fad7c82
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_chromium_rel_ng
Reviewed-on: https://chromium-review.googlesource.com/575519Reviewed-by: 's avatarDmitry Gozman <dgozman@chromium.org>
Commit-Queue: Aleksey Kozyatinskiy <kozyatinskiy@chromium.org>
Cr-Original-Commit-Position: refs/heads/master@{#46849}
Reviewed-on: https://chromium-review.googlesource.com/596549
Cr-Commit-Position: refs/heads/master@{#47060}
parent 25f03308
...@@ -15,6 +15,39 @@ ...@@ -15,6 +15,39 @@
namespace v8_inspector { namespace v8_inspector {
class InspectedContext::WeakCallbackData {
public:
WeakCallbackData(InspectedContext* context, V8InspectorImpl* inspector,
int groupId, int contextId)
: m_context(context),
m_inspector(inspector),
m_groupId(groupId),
m_contextId(contextId) {}
static void resetContext(const v8::WeakCallbackInfo<WeakCallbackData>& data) {
// InspectedContext is alive here because weak handler is still alive.
data.GetParameter()->m_context->m_weakCallbackData = nullptr;
data.GetParameter()->m_context->m_context.Reset();
data.SetSecondPassCallback(&callContextCollected);
}
static void callContextCollected(
const v8::WeakCallbackInfo<WeakCallbackData>& data) {
// InspectedContext can be dead here since anything can happen between first
// and second pass callback.
WeakCallbackData* callbackData = data.GetParameter();
callbackData->m_inspector->contextCollected(callbackData->m_groupId,
callbackData->m_contextId);
delete callbackData;
}
private:
InspectedContext* m_context;
V8InspectorImpl* m_inspector;
int m_groupId;
int m_contextId;
};
InspectedContext::InspectedContext(V8InspectorImpl* inspector, InspectedContext::InspectedContext(V8InspectorImpl* inspector,
const V8ContextInfo& info, int contextId) const V8ContextInfo& info, int contextId)
: m_inspector(inspector), : m_inspector(inspector),
...@@ -25,6 +58,11 @@ InspectedContext::InspectedContext(V8InspectorImpl* inspector, ...@@ -25,6 +58,11 @@ InspectedContext::InspectedContext(V8InspectorImpl* inspector,
m_humanReadableName(toString16(info.humanReadableName)), m_humanReadableName(toString16(info.humanReadableName)),
m_auxData(toString16(info.auxData)) { m_auxData(toString16(info.auxData)) {
v8::debug::SetContextId(info.context, contextId); v8::debug::SetContextId(info.context, contextId);
m_weakCallbackData =
new WeakCallbackData(this, m_inspector, m_contextGroupId, m_contextId);
m_context.SetWeak(m_weakCallbackData,
&InspectedContext::WeakCallbackData::resetContext,
v8::WeakCallbackType::kParameter);
if (!info.hasMemoryOnConsole) return; if (!info.hasMemoryOnConsole) return;
v8::Context::Scope contextScope(info.context); v8::Context::Scope contextScope(info.context);
v8::Local<v8::Object> global = info.context->Global(); v8::Local<v8::Object> global = info.context->Global();
...@@ -38,6 +76,9 @@ InspectedContext::InspectedContext(V8InspectorImpl* inspector, ...@@ -38,6 +76,9 @@ InspectedContext::InspectedContext(V8InspectorImpl* inspector,
} }
InspectedContext::~InspectedContext() { InspectedContext::~InspectedContext() {
// If we destory InspectedContext before weak callback is invoked then we need
// to delete data here.
if (!m_context.IsEmpty()) delete m_weakCallbackData;
} }
// static // static
......
...@@ -47,6 +47,8 @@ class InspectedContext { ...@@ -47,6 +47,8 @@ class InspectedContext {
friend class V8InspectorImpl; friend class V8InspectorImpl;
InspectedContext(V8InspectorImpl*, const V8ContextInfo&, int contextId); InspectedContext(V8InspectorImpl*, const V8ContextInfo&, int contextId);
class WeakCallbackData;
V8InspectorImpl* m_inspector; V8InspectorImpl* m_inspector;
v8::Global<v8::Context> m_context; v8::Global<v8::Context> m_context;
int m_contextId; int m_contextId;
...@@ -56,6 +58,7 @@ class InspectedContext { ...@@ -56,6 +58,7 @@ class InspectedContext {
const String16 m_auxData; const String16 m_auxData;
std::unordered_set<int> m_reportedSessionIds; std::unordered_set<int> m_reportedSessionIds;
std::unordered_map<int, std::unique_ptr<InjectedScript>> m_injectedScripts; std::unordered_map<int, std::unique_ptr<InjectedScript>> m_injectedScripts;
WeakCallbackData* m_weakCallbackData;
DISALLOW_COPY_AND_ASSIGN(InspectedContext); DISALLOW_COPY_AND_ASSIGN(InspectedContext);
}; };
......
...@@ -203,6 +203,10 @@ void V8InspectorImpl::contextCreated(const V8ContextInfo& info) { ...@@ -203,6 +203,10 @@ void V8InspectorImpl::contextCreated(const V8ContextInfo& info) {
void V8InspectorImpl::contextDestroyed(v8::Local<v8::Context> context) { void V8InspectorImpl::contextDestroyed(v8::Local<v8::Context> context) {
int contextId = InspectedContext::contextId(context); int contextId = InspectedContext::contextId(context);
int groupId = contextGroupId(context); int groupId = contextGroupId(context);
contextCollected(groupId, contextId);
}
void V8InspectorImpl::contextCollected(int groupId, int contextId) {
m_contextIdToGroupIdMap.erase(contextId); m_contextIdToGroupIdMap.erase(contextId);
ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(groupId); ConsoleStorageMap::iterator storageIt = m_consoleStorageMap.find(groupId);
......
...@@ -74,6 +74,7 @@ class V8InspectorImpl : public V8Inspector { ...@@ -74,6 +74,7 @@ class V8InspectorImpl : public V8Inspector {
const StringView& state) override; const StringView& state) override;
void contextCreated(const V8ContextInfo&) override; void contextCreated(const V8ContextInfo&) override;
void contextDestroyed(v8::Local<v8::Context>) override; void contextDestroyed(v8::Local<v8::Context>) override;
void contextCollected(int contextGroupId, int contextId);
void resetContextGroup(int contextGroupId) override; void resetContextGroup(int contextGroupId) override;
void idleStarted() override; void idleStarted() override;
void idleFinished() override; void idleFinished() override;
......
...@@ -642,6 +642,9 @@ class InspectorExtension : public IsolateData::SetupGlobalTask { ...@@ -642,6 +642,9 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
inspector->Set(ToV8String(isolate, "fireContextDestroyed"), inspector->Set(ToV8String(isolate, "fireContextDestroyed"),
v8::FunctionTemplate::New( v8::FunctionTemplate::New(
isolate, &InspectorExtension::FireContextDestroyed)); isolate, &InspectorExtension::FireContextDestroyed));
inspector->Set(
ToV8String(isolate, "freeContext"),
v8::FunctionTemplate::New(isolate, &InspectorExtension::FreeContext));
inspector->Set(ToV8String(isolate, "addInspectedObject"), inspector->Set(ToV8String(isolate, "addInspectedObject"),
v8::FunctionTemplate::New( v8::FunctionTemplate::New(
isolate, &InspectorExtension::AddInspectedObject)); isolate, &InspectorExtension::AddInspectedObject));
...@@ -683,6 +686,12 @@ class InspectorExtension : public IsolateData::SetupGlobalTask { ...@@ -683,6 +686,12 @@ class InspectorExtension : public IsolateData::SetupGlobalTask {
data->FireContextDestroyed(context); data->FireContextDestroyed(context);
} }
static void FreeContext(const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
IsolateData* data = IsolateData::FromContext(context);
data->FreeContext(context);
}
static void AddInspectedObject( static void AddInspectedObject(
const v8::FunctionCallbackInfo<v8::Value>& args) { const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() != 2 || !args[0]->IsInt32()) { if (args.Length() != 2 || !args[0]->IsInt32()) {
......
...@@ -303,6 +303,13 @@ void IsolateData::FireContextDestroyed(v8::Local<v8::Context> context) { ...@@ -303,6 +303,13 @@ void IsolateData::FireContextDestroyed(v8::Local<v8::Context> context) {
inspector_->contextDestroyed(context); inspector_->contextDestroyed(context);
} }
void IsolateData::FreeContext(v8::Local<v8::Context> context) {
int context_group_id = GetContextGroupId(context);
auto it = contexts_.find(context_group_id);
if (it == contexts_.end()) return;
contexts_.erase(it);
}
std::vector<int> IsolateData::GetSessionIds(int context_group_id) { std::vector<int> IsolateData::GetSessionIds(int context_group_id) {
std::vector<int> result; std::vector<int> result;
for (auto& it : sessions_) { for (auto& it : sessions_) {
......
...@@ -68,6 +68,7 @@ class IsolateData : public v8_inspector::V8InspectorClient { ...@@ -68,6 +68,7 @@ class IsolateData : public v8_inspector::V8InspectorClient {
void DumpAsyncTaskStacksStateForTest(); void DumpAsyncTaskStacksStateForTest();
void FireContextCreated(v8::Local<v8::Context> context, int context_group_id); void FireContextCreated(v8::Local<v8::Context> context, int context_group_id);
void FireContextDestroyed(v8::Local<v8::Context> context); void FireContextDestroyed(v8::Local<v8::Context> context);
void FreeContext(v8::Local<v8::Context> context);
private: private:
struct VectorCompare { struct VectorCompare {
......
Tests that contextDesrtoyed nofitication is fired when context is collected.
{
method : Runtime.executionContextDestroyed
params : {
executionContextId : <executionContextId>
}
}
// Copyright 2017 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.
let {session, contextGroup, Protocol} =
InspectorTest.start('Tests that contextDesrtoyed nofitication is fired when context is collected.');
(async function test() {
await Protocol.Runtime.enable();
Protocol.Runtime.onExecutionContextDestroyed(InspectorTest.logMessage);
contextGroup.addScript('inspector.freeContext()');
await Protocol.HeapProfiler.collectGarbage();
InspectorTest.completeTest();
})();
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