1 // Copyright 2016 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/inspector/inspected-context.h"
6
7 #include "include/v8-context.h"
8 #include "include/v8-inspector.h"
9 #include "src/debug/debug-interface.h"
10 #include "src/inspector/injected-script.h"
11 #include "src/inspector/string-util.h"
12 #include "src/inspector/v8-console.h"
13 #include "src/inspector/v8-inspector-impl.h"
14
15 namespace v8_inspector {
16
17 class InspectedContext::WeakCallbackData {
18 public:
WeakCallbackData(InspectedContext * context,V8InspectorImpl * inspector,int groupId,int contextId)19 WeakCallbackData(InspectedContext* context, V8InspectorImpl* inspector,
20 int groupId, int contextId)
21 : m_context(context),
22 m_inspector(inspector),
23 m_groupId(groupId),
24 m_contextId(contextId) {}
25
resetContext(const v8::WeakCallbackInfo<WeakCallbackData> & data)26 static void resetContext(const v8::WeakCallbackInfo<WeakCallbackData>& data) {
27 // InspectedContext is alive here because weak handler is still alive.
28 data.GetParameter()->m_context->m_weakCallbackData = nullptr;
29 data.GetParameter()->m_context->m_context.Reset();
30 data.SetSecondPassCallback(&callContextCollected);
31 }
32
callContextCollected(const v8::WeakCallbackInfo<WeakCallbackData> & data)33 static void callContextCollected(
34 const v8::WeakCallbackInfo<WeakCallbackData>& data) {
35 // InspectedContext can be dead here since anything can happen between first
36 // and second pass callback.
37 WeakCallbackData* callbackData = data.GetParameter();
38 callbackData->m_inspector->contextCollected(callbackData->m_groupId,
39 callbackData->m_contextId);
40 delete callbackData;
41 }
42
43 private:
44 InspectedContext* m_context;
45 V8InspectorImpl* m_inspector;
46 int m_groupId;
47 int m_contextId;
48 };
49
InspectedContext(V8InspectorImpl * inspector,const V8ContextInfo & info,int contextId)50 InspectedContext::InspectedContext(V8InspectorImpl* inspector,
51 const V8ContextInfo& info, int contextId)
52 : m_inspector(inspector),
53 m_context(info.context->GetIsolate(), info.context),
54 m_contextId(contextId),
55 m_contextGroupId(info.contextGroupId),
56 m_origin(toString16(info.origin)),
57 m_humanReadableName(toString16(info.humanReadableName)),
58 m_auxData(toString16(info.auxData)),
59 m_uniqueId(internal::V8DebuggerId::generate(inspector)) {
60 v8::debug::SetContextId(info.context, contextId);
61 m_weakCallbackData =
62 new WeakCallbackData(this, m_inspector, m_contextGroupId, m_contextId);
63 m_context.SetWeak(m_weakCallbackData,
64 &InspectedContext::WeakCallbackData::resetContext,
65 v8::WeakCallbackType::kParameter);
66
67 v8::Context::Scope contextScope(info.context);
68 v8::HandleScope handleScope(info.context->GetIsolate());
69 v8::Local<v8::Object> global = info.context->Global();
70 v8::Local<v8::Value> console;
71 if (!global
72 ->Get(info.context,
73 toV8String(info.context->GetIsolate(), "console"))
74 .ToLocal(&console) ||
75 !console->IsObject()) {
76 return;
77 }
78
79 if (v8::debug::isExperimentalAsyncStackTaggingApiEnabled()) {
80 m_inspector->console()->installAsyncStackTaggingAPI(
81 info.context, console.As<v8::Object>());
82 }
83
84 if (info.hasMemoryOnConsole) {
85 m_inspector->console()->installMemoryGetter(info.context,
86 console.As<v8::Object>());
87 }
88 }
89
~InspectedContext()90 InspectedContext::~InspectedContext() {
91 // If we destory InspectedContext before weak callback is invoked then we need
92 // to delete data here.
93 if (!m_context.IsEmpty()) delete m_weakCallbackData;
94 }
95
96 // static
contextId(v8::Local<v8::Context> context)97 int InspectedContext::contextId(v8::Local<v8::Context> context) {
98 return v8::debug::GetContextId(context);
99 }
100
context() const101 v8::Local<v8::Context> InspectedContext::context() const {
102 return m_context.Get(isolate());
103 }
104
isolate() const105 v8::Isolate* InspectedContext::isolate() const {
106 return m_inspector->isolate();
107 }
108
isReported(int sessionId) const109 bool InspectedContext::isReported(int sessionId) const {
110 return m_reportedSessionIds.find(sessionId) != m_reportedSessionIds.cend();
111 }
112
setReported(int sessionId,bool reported)113 void InspectedContext::setReported(int sessionId, bool reported) {
114 if (reported)
115 m_reportedSessionIds.insert(sessionId);
116 else
117 m_reportedSessionIds.erase(sessionId);
118 }
119
getInjectedScript(int sessionId)120 InjectedScript* InspectedContext::getInjectedScript(int sessionId) {
121 auto it = m_injectedScripts.find(sessionId);
122 return it == m_injectedScripts.end() ? nullptr : it->second.get();
123 }
124
createInjectedScript(int sessionId)125 InjectedScript* InspectedContext::createInjectedScript(int sessionId) {
126 std::unique_ptr<InjectedScript> injectedScript =
127 std::make_unique<InjectedScript>(this, sessionId);
128 CHECK(m_injectedScripts.find(sessionId) == m_injectedScripts.end());
129 m_injectedScripts[sessionId] = std::move(injectedScript);
130 return getInjectedScript(sessionId);
131 }
132
discardInjectedScript(int sessionId)133 void InspectedContext::discardInjectedScript(int sessionId) {
134 m_injectedScripts.erase(sessionId);
135 }
136
addInternalObject(v8::Local<v8::Object> object,V8InternalValueType type)137 bool InspectedContext::addInternalObject(v8::Local<v8::Object> object,
138 V8InternalValueType type) {
139 if (m_internalObjects.IsEmpty()) {
140 m_internalObjects.Reset(isolate(),
141 v8::debug::EphemeronTable::New(isolate()));
142 }
143 v8::Local<v8::debug::EphemeronTable> new_map =
144 m_internalObjects.Get(isolate())->Set(
145 isolate(), object,
146 v8::Integer::New(isolate(), static_cast<int>(type)));
147 m_internalObjects.Reset(isolate(), new_map);
148 return true;
149 }
150
getInternalType(v8::Local<v8::Object> object)151 V8InternalValueType InspectedContext::getInternalType(
152 v8::Local<v8::Object> object) {
153 if (m_internalObjects.IsEmpty()) return V8InternalValueType::kNone;
154 v8::Local<v8::Value> typeValue;
155 if (!m_internalObjects.Get(isolate())
156 ->Get(isolate(), object)
157 .ToLocal(&typeValue) ||
158 !typeValue->IsUint32()) {
159 return V8InternalValueType::kNone;
160 }
161 return static_cast<V8InternalValueType>(typeValue.As<v8::Int32>()->Value());
162 }
163
164 } // namespace v8_inspector
165