| OLD | NEW |
| (Empty) |
| 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 "test/inspector/inspector-impl.h" | |
| 6 | |
| 7 #include "include/v8.h" | |
| 8 | |
| 9 #include "src/vector.h" | |
| 10 #include "test/inspector/isolate-data.h" | |
| 11 #include "test/inspector/task-runner.h" | |
| 12 | |
| 13 namespace { | |
| 14 | |
| 15 class ChannelImpl final : public v8_inspector::V8Inspector::Channel { | |
| 16 public: | |
| 17 ChannelImpl(InspectorClientImpl::FrontendChannel* frontend_channel, | |
| 18 int session_id) | |
| 19 : frontend_channel_(frontend_channel), session_id_(session_id) {} | |
| 20 virtual ~ChannelImpl() = default; | |
| 21 | |
| 22 private: | |
| 23 void sendResponse( | |
| 24 int callId, | |
| 25 std::unique_ptr<v8_inspector::StringBuffer> message) override { | |
| 26 frontend_channel_->SendMessageToFrontend(session_id_, message->string()); | |
| 27 } | |
| 28 void sendNotification( | |
| 29 std::unique_ptr<v8_inspector::StringBuffer> message) override { | |
| 30 frontend_channel_->SendMessageToFrontend(session_id_, message->string()); | |
| 31 } | |
| 32 void flushProtocolNotifications() override {} | |
| 33 | |
| 34 InspectorClientImpl::FrontendChannel* frontend_channel_; | |
| 35 int session_id_; | |
| 36 DISALLOW_COPY_AND_ASSIGN(ChannelImpl); | |
| 37 }; | |
| 38 | |
| 39 v8::internal::Vector<uint16_t> ToVector(v8::Local<v8::String> str) { | |
| 40 v8::internal::Vector<uint16_t> buffer = | |
| 41 v8::internal::Vector<uint16_t>::New(str->Length()); | |
| 42 str->Write(buffer.start(), 0, str->Length()); | |
| 43 return buffer; | |
| 44 } | |
| 45 | |
| 46 void MessageHandler(v8::Local<v8::Message> message, | |
| 47 v8::Local<v8::Value> exception) { | |
| 48 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | |
| 49 v8::Local<v8::Context> context = isolate->GetEnteredContext(); | |
| 50 if (context.IsEmpty()) return; | |
| 51 v8_inspector::V8Inspector* inspector = | |
| 52 IsolateData::FromContext(context)->inspector()->inspector(); | |
| 53 | |
| 54 v8::Local<v8::StackTrace> stack = message->GetStackTrace(); | |
| 55 int script_id = | |
| 56 static_cast<int>(message->GetScriptOrigin().ScriptID()->Value()); | |
| 57 if (!stack.IsEmpty() && stack->GetFrameCount() > 0) { | |
| 58 int top_script_id = stack->GetFrame(0)->GetScriptId(); | |
| 59 if (top_script_id == script_id) script_id = 0; | |
| 60 } | |
| 61 int line_number = message->GetLineNumber(context).FromMaybe(0); | |
| 62 int column_number = 0; | |
| 63 if (message->GetStartColumn(context).IsJust()) | |
| 64 column_number = message->GetStartColumn(context).FromJust() + 1; | |
| 65 | |
| 66 v8_inspector::StringView detailed_message; | |
| 67 v8::internal::Vector<uint16_t> message_text_string = ToVector(message->Get()); | |
| 68 v8_inspector::StringView message_text(message_text_string.start(), | |
| 69 message_text_string.length()); | |
| 70 v8::internal::Vector<uint16_t> url_string; | |
| 71 if (message->GetScriptOrigin().ResourceName()->IsString()) { | |
| 72 url_string = | |
| 73 ToVector(message->GetScriptOrigin().ResourceName().As<v8::String>()); | |
| 74 } | |
| 75 v8_inspector::StringView url(url_string.start(), url_string.length()); | |
| 76 | |
| 77 inspector->exceptionThrown(context, message_text, exception, detailed_message, | |
| 78 url, line_number, column_number, | |
| 79 inspector->createStackTrace(stack), script_id); | |
| 80 } | |
| 81 | |
| 82 v8::Local<v8::String> ToString(v8::Isolate* isolate, | |
| 83 const v8_inspector::StringView& string) { | |
| 84 if (string.is8Bit()) | |
| 85 return v8::String::NewFromOneByte(isolate, string.characters8(), | |
| 86 v8::NewStringType::kNormal, | |
| 87 static_cast<int>(string.length())) | |
| 88 .ToLocalChecked(); | |
| 89 else | |
| 90 return v8::String::NewFromTwoByte(isolate, string.characters16(), | |
| 91 v8::NewStringType::kNormal, | |
| 92 static_cast<int>(string.length())) | |
| 93 .ToLocalChecked(); | |
| 94 } | |
| 95 | |
| 96 void Print(v8::Isolate* isolate, const v8_inspector::StringView& string) { | |
| 97 v8::Local<v8::String> v8_string = ToString(isolate, string); | |
| 98 v8::String::Utf8Value utf8_string(v8_string); | |
| 99 fwrite(*utf8_string, sizeof(**utf8_string), utf8_string.length(), stdout); | |
| 100 } | |
| 101 } // namespace | |
| 102 | |
| 103 InspectorClientImpl::InspectorClientImpl(v8::Isolate* isolate, | |
| 104 TaskRunner* task_runner, | |
| 105 FrontendChannel* frontend_channel) | |
| 106 : task_runner_(task_runner), | |
| 107 isolate_(isolate), | |
| 108 frontend_channel_(frontend_channel) { | |
| 109 isolate_->AddMessageListener(MessageHandler); | |
| 110 inspector_ = v8_inspector::V8Inspector::create(isolate_, this); | |
| 111 } | |
| 112 | |
| 113 InspectorClientImpl::~InspectorClientImpl() {} | |
| 114 | |
| 115 int InspectorClientImpl::ConnectSession(int context_group_id, | |
| 116 const v8_inspector::StringView& state) { | |
| 117 int session_id = ++last_session_id_; | |
| 118 channels_[session_id].reset(new ChannelImpl(frontend_channel_, session_id)); | |
| 119 sessions_[session_id] = | |
| 120 inspector_->connect(context_group_id, channels_[session_id].get(), state); | |
| 121 context_group_by_session_[sessions_[session_id].get()] = context_group_id; | |
| 122 return session_id; | |
| 123 } | |
| 124 | |
| 125 std::unique_ptr<v8_inspector::StringBuffer> | |
| 126 InspectorClientImpl::DisconnectSession(int session_id) { | |
| 127 auto it = sessions_.find(session_id); | |
| 128 CHECK(it != sessions_.end()); | |
| 129 context_group_by_session_.erase(it->second.get()); | |
| 130 std::unique_ptr<v8_inspector::StringBuffer> result = it->second->stateJSON(); | |
| 131 sessions_.erase(it); | |
| 132 channels_.erase(session_id); | |
| 133 return result; | |
| 134 } | |
| 135 | |
| 136 void InspectorClientImpl::SendMessage(int session_id, | |
| 137 const v8_inspector::StringView& message) { | |
| 138 auto it = sessions_.find(session_id); | |
| 139 if (it != sessions_.end()) it->second->dispatchProtocolMessage(message); | |
| 140 } | |
| 141 | |
| 142 void InspectorClientImpl::BreakProgram( | |
| 143 int context_group_id, const v8_inspector::StringView& reason, | |
| 144 const v8_inspector::StringView& details) { | |
| 145 for (int session_id : GetSessionIds(context_group_id)) { | |
| 146 auto it = sessions_.find(session_id); | |
| 147 if (it != sessions_.end()) it->second->breakProgram(reason, details); | |
| 148 } | |
| 149 } | |
| 150 | |
| 151 void InspectorClientImpl::SchedulePauseOnNextStatement( | |
| 152 int context_group_id, const v8_inspector::StringView& reason, | |
| 153 const v8_inspector::StringView& details) { | |
| 154 for (int session_id : GetSessionIds(context_group_id)) { | |
| 155 auto it = sessions_.find(session_id); | |
| 156 if (it != sessions_.end()) | |
| 157 it->second->schedulePauseOnNextStatement(reason, details); | |
| 158 } | |
| 159 } | |
| 160 | |
| 161 void InspectorClientImpl::CancelPauseOnNextStatement(int context_group_id) { | |
| 162 for (int session_id : GetSessionIds(context_group_id)) { | |
| 163 auto it = sessions_.find(session_id); | |
| 164 if (it != sessions_.end()) it->second->cancelPauseOnNextStatement(); | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 void InspectorClientImpl::ContextCreated(v8::Local<v8::Context> context, | |
| 169 int context_group_id) { | |
| 170 v8_inspector::V8ContextInfo info(context, context_group_id, | |
| 171 v8_inspector::StringView()); | |
| 172 info.hasMemoryOnConsole = true; | |
| 173 inspector_->contextCreated(info); | |
| 174 } | |
| 175 | |
| 176 void InspectorClientImpl::ContextDestroyed(v8::Local<v8::Context> context) { | |
| 177 inspector_->contextDestroyed(context); | |
| 178 } | |
| 179 | |
| 180 std::vector<int> InspectorClientImpl::GetSessionIds(int context_group_id) { | |
| 181 std::vector<int> result; | |
| 182 for (auto& it : sessions_) { | |
| 183 if (context_group_by_session_[it.second.get()] == context_group_id) | |
| 184 result.push_back(it.first); | |
| 185 } | |
| 186 return result; | |
| 187 } | |
| 188 | |
| 189 bool InspectorClientImpl::formatAccessorsAsProperties( | |
| 190 v8::Local<v8::Value> object) { | |
| 191 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | |
| 192 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | |
| 193 v8::Local<v8::Private> shouldFormatAccessorsPrivate = v8::Private::ForApi( | |
| 194 isolate, v8::String::NewFromUtf8(isolate, "allowAccessorFormatting", | |
| 195 v8::NewStringType::kNormal) | |
| 196 .ToLocalChecked()); | |
| 197 CHECK(object->IsObject()); | |
| 198 return object.As<v8::Object>() | |
| 199 ->HasPrivate(context, shouldFormatAccessorsPrivate) | |
| 200 .FromMaybe(false); | |
| 201 } | |
| 202 | |
| 203 v8::Local<v8::Context> InspectorClientImpl::ensureDefaultContextInGroup( | |
| 204 int context_group_id) { | |
| 205 CHECK(isolate_); | |
| 206 return task_runner_->data()->GetContext(context_group_id); | |
| 207 } | |
| 208 | |
| 209 void InspectorClientImpl::SetCurrentTimeMSForTest(double time) { | |
| 210 current_time_ = time; | |
| 211 current_time_set_for_test_ = true; | |
| 212 } | |
| 213 | |
| 214 double InspectorClientImpl::currentTimeMS() { | |
| 215 if (current_time_set_for_test_) return current_time_; | |
| 216 return v8::base::OS::TimeCurrentMillis(); | |
| 217 } | |
| 218 | |
| 219 void InspectorClientImpl::SetMemoryInfoForTest( | |
| 220 v8::Local<v8::Value> memory_info) { | |
| 221 memory_info_.Reset(isolate_, memory_info); | |
| 222 } | |
| 223 | |
| 224 void InspectorClientImpl::SetLogConsoleApiMessageCalls(bool log) { | |
| 225 log_console_api_message_calls_ = log; | |
| 226 } | |
| 227 | |
| 228 v8::MaybeLocal<v8::Value> InspectorClientImpl::memoryInfo( | |
| 229 v8::Isolate* isolate, v8::Local<v8::Context>) { | |
| 230 if (memory_info_.IsEmpty()) return v8::MaybeLocal<v8::Value>(); | |
| 231 return memory_info_.Get(isolate); | |
| 232 } | |
| 233 | |
| 234 void InspectorClientImpl::runMessageLoopOnPause(int) { | |
| 235 task_runner_->RunMessageLoop(true); | |
| 236 } | |
| 237 | |
| 238 void InspectorClientImpl::quitMessageLoopOnPause() { | |
| 239 task_runner_->QuitMessageLoop(); | |
| 240 } | |
| 241 | |
| 242 void InspectorClientImpl::consoleAPIMessage( | |
| 243 int contextGroupId, v8::Isolate::MessageErrorLevel level, | |
| 244 const v8_inspector::StringView& message, | |
| 245 const v8_inspector::StringView& url, unsigned lineNumber, | |
| 246 unsigned columnNumber, v8_inspector::V8StackTrace* stack) { | |
| 247 if (!log_console_api_message_calls_) return; | |
| 248 Print(isolate_, message); | |
| 249 fprintf(stdout, " ("); | |
| 250 Print(isolate_, url); | |
| 251 fprintf(stdout, ":%d:%d)", lineNumber, columnNumber); | |
| 252 Print(isolate_, stack->toString()->string()); | |
| 253 fprintf(stdout, "\n"); | |
| 254 } | |
| OLD | NEW |