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 15namespace v8_inspector { 16 17class InspectedContext::WeakCallbackData { 18 public: 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 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 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 50InspectedContext::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 90InspectedContext::~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 97int InspectedContext::contextId(v8::Local<v8::Context> context) { 98 return v8::debug::GetContextId(context); 99} 100 101v8::Local<v8::Context> InspectedContext::context() const { 102 return m_context.Get(isolate()); 103} 104 105v8::Isolate* InspectedContext::isolate() const { 106 return m_inspector->isolate(); 107} 108 109bool InspectedContext::isReported(int sessionId) const { 110 return m_reportedSessionIds.find(sessionId) != m_reportedSessionIds.cend(); 111} 112 113void InspectedContext::setReported(int sessionId, bool reported) { 114 if (reported) 115 m_reportedSessionIds.insert(sessionId); 116 else 117 m_reportedSessionIds.erase(sessionId); 118} 119 120InjectedScript* InspectedContext::getInjectedScript(int sessionId) { 121 auto it = m_injectedScripts.find(sessionId); 122 return it == m_injectedScripts.end() ? nullptr : it->second.get(); 123} 124 125InjectedScript* 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 133void InspectedContext::discardInjectedScript(int sessionId) { 134 m_injectedScripts.erase(sessionId); 135} 136 137bool 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 151V8InternalValueType 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