| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #if !defined(_WIN32) && !defined(_WIN64) | 5 #if !defined(_WIN32) && !defined(_WIN64) |
| 6 #include <unistd.h> // NOLINT | 6 #include <unistd.h> // NOLINT |
| 7 #endif // !defined(_WIN32) && !defined(_WIN64) | 7 #endif // !defined(_WIN32) && !defined(_WIN64) |
| 8 | 8 |
| 9 #include <locale.h> | 9 #include <locale.h> |
| 10 | 10 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 44 v8::internal::Vector<uint16_t>::New(str->Length()); | 44 v8::internal::Vector<uint16_t>::New(str->Length()); |
| 45 str->Write(buffer.start(), 0, str->Length()); | 45 str->Write(buffer.start(), 0, str->Length()); |
| 46 return buffer; | 46 return buffer; |
| 47 } | 47 } |
| 48 | 48 |
| 49 v8::Local<v8::String> ToV8String(v8::Isolate* isolate, const char* str) { | 49 v8::Local<v8::String> ToV8String(v8::Isolate* isolate, const char* str) { |
| 50 return v8::String::NewFromUtf8(isolate, str, v8::NewStringType::kNormal) | 50 return v8::String::NewFromUtf8(isolate, str, v8::NewStringType::kNormal) |
| 51 .ToLocalChecked(); | 51 .ToLocalChecked(); |
| 52 } | 52 } |
| 53 | 53 |
| 54 v8::internal::Vector<uint16_t> ToVector( |
| 55 const v8_inspector::StringView& string) { |
| 56 v8::internal::Vector<uint16_t> buffer = |
| 57 v8::internal::Vector<uint16_t>::New(static_cast<int>(string.length())); |
| 58 for (size_t i = 0; i < string.length(); i++) { |
| 59 if (string.is8Bit()) |
| 60 buffer[i] = string.characters8()[i]; |
| 61 else |
| 62 buffer[i] = string.characters16()[i]; |
| 63 } |
| 64 return buffer; |
| 65 } |
| 66 |
| 67 class CreateContextGroupTask : public TaskRunner::Task { |
| 68 public: |
| 69 CreateContextGroupTask(v8::base::Semaphore* ready_semaphore, |
| 70 int* context_group_id) |
| 71 : ready_semaphore_(ready_semaphore), |
| 72 context_group_id_(context_group_id) {} |
| 73 virtual ~CreateContextGroupTask() = default; |
| 74 bool is_inspector_task() final { return true; } |
| 75 |
| 76 private: |
| 77 void Run() override { |
| 78 *context_group_id_ = data()->CreateContextGroup(); |
| 79 if (ready_semaphore_) ready_semaphore_->Signal(); |
| 80 } |
| 81 |
| 82 v8::base::Semaphore* ready_semaphore_; |
| 83 int* context_group_id_; |
| 84 }; |
| 85 |
| 86 class ConnectSessionTask : public TaskRunner::Task { |
| 87 public: |
| 88 ConnectSessionTask(v8::base::Semaphore* ready_semaphore, int context_group_id, |
| 89 const v8::internal::Vector<uint16_t>& state, |
| 90 int* session_id) |
| 91 : ready_semaphore_(ready_semaphore), |
| 92 context_group_id_(context_group_id), |
| 93 state_(state), |
| 94 session_id_(session_id) {} |
| 95 virtual ~ConnectSessionTask() = default; |
| 96 bool is_inspector_task() final { return true; } |
| 97 |
| 98 private: |
| 99 void Run() override { |
| 100 v8_inspector::StringView state(state_.start(), state_.length()); |
| 101 *session_id_ = |
| 102 data()->inspector()->ConnectSession(context_group_id_, state); |
| 103 if (ready_semaphore_) ready_semaphore_->Signal(); |
| 104 } |
| 105 |
| 106 v8::base::Semaphore* ready_semaphore_; |
| 107 int context_group_id_; |
| 108 const v8::internal::Vector<uint16_t>& state_; |
| 109 int* session_id_; |
| 110 }; |
| 111 |
| 112 class DisconnectSessionTask : public TaskRunner::Task { |
| 113 public: |
| 114 DisconnectSessionTask(v8::base::Semaphore* ready_semaphore, int session_id, |
| 115 v8::internal::Vector<uint16_t>* state) |
| 116 : ready_semaphore_(ready_semaphore), |
| 117 session_id_(session_id), |
| 118 state_(state) {} |
| 119 virtual ~DisconnectSessionTask() = default; |
| 120 bool is_inspector_task() final { return true; } |
| 121 |
| 122 private: |
| 123 void Run() override { |
| 124 std::unique_ptr<v8_inspector::StringBuffer> state = |
| 125 data()->inspector()->DisconnectSession(session_id_); |
| 126 *state_ = ToVector(state->string()); |
| 127 if (ready_semaphore_) ready_semaphore_->Signal(); |
| 128 } |
| 129 |
| 130 v8::base::Semaphore* ready_semaphore_; |
| 131 int session_id_; |
| 132 v8::internal::Vector<uint16_t>* state_; |
| 133 }; |
| 134 |
| 135 class SendMessageToBackendTask : public TaskRunner::Task { |
| 136 public: |
| 137 explicit SendMessageToBackendTask( |
| 138 int session_id, const v8::internal::Vector<uint16_t>& message) |
| 139 : session_id_(session_id), message_(message) {} |
| 140 bool is_inspector_task() final { return true; } |
| 141 |
| 142 private: |
| 143 void Run() override { |
| 144 v8_inspector::StringView message_view(message_.start(), message_.length()); |
| 145 data()->inspector()->SendMessage(session_id_, message_view); |
| 146 } |
| 147 |
| 148 int session_id_; |
| 149 v8::internal::Vector<uint16_t> message_; |
| 150 }; |
| 151 |
| 152 class SchedulePauseOnNextStatementTask : public TaskRunner::Task { |
| 153 public: |
| 154 SchedulePauseOnNextStatementTask( |
| 155 v8::base::Semaphore* ready_semaphore, int context_group_id, |
| 156 const v8::internal::Vector<uint16_t>& reason, |
| 157 const v8::internal::Vector<uint16_t>& details) |
| 158 : ready_semaphore_(ready_semaphore), |
| 159 context_group_id_(context_group_id), |
| 160 reason_(reason), |
| 161 details_(details) {} |
| 162 virtual ~SchedulePauseOnNextStatementTask() = default; |
| 163 bool is_inspector_task() final { return true; } |
| 164 |
| 165 private: |
| 166 void Run() override { |
| 167 v8_inspector::StringView reason(reason_.start(), reason_.length()); |
| 168 v8_inspector::StringView details(details_.start(), details_.length()); |
| 169 data()->inspector()->SchedulePauseOnNextStatement(context_group_id_, reason, |
| 170 details); |
| 171 if (ready_semaphore_) ready_semaphore_->Signal(); |
| 172 } |
| 173 |
| 174 v8::base::Semaphore* ready_semaphore_; |
| 175 int context_group_id_; |
| 176 const v8::internal::Vector<uint16_t>& reason_; |
| 177 const v8::internal::Vector<uint16_t>& details_; |
| 178 }; |
| 179 |
| 180 class CancelPauseOnNextStatementTask : public TaskRunner::Task { |
| 181 public: |
| 182 CancelPauseOnNextStatementTask(v8::base::Semaphore* ready_semaphore, |
| 183 int context_group_id) |
| 184 : ready_semaphore_(ready_semaphore), |
| 185 context_group_id_(context_group_id) {} |
| 186 virtual ~CancelPauseOnNextStatementTask() = default; |
| 187 bool is_inspector_task() final { return true; } |
| 188 |
| 189 private: |
| 190 void Run() override { |
| 191 data()->inspector()->CancelPauseOnNextStatement(context_group_id_); |
| 192 if (ready_semaphore_) ready_semaphore_->Signal(); |
| 193 } |
| 194 |
| 195 v8::base::Semaphore* ready_semaphore_; |
| 196 int context_group_id_; |
| 197 }; |
| 198 |
| 199 class SendMessageToFrontendTask : public TaskRunner::Task { |
| 200 public: |
| 201 SendMessageToFrontendTask(int context_group_id, int session_id, |
| 202 const v8::internal::Vector<uint16_t>& message) |
| 203 : context_group_id_(context_group_id), |
| 204 session_id_(session_id), |
| 205 message_(message) {} |
| 206 virtual ~SendMessageToFrontendTask() {} |
| 207 |
| 208 bool is_inspector_task() final { return false; } |
| 209 |
| 210 static void Register(int session_id, v8::Isolate* isolate, |
| 211 v8::Local<v8::Function> dispatcher) { |
| 212 dispatchers_[session_id].Reset(isolate, dispatcher); |
| 213 } |
| 214 |
| 215 static void Unregister(int session_id) { dispatchers_.erase(session_id); } |
| 216 |
| 217 private: |
| 218 void Run() override { |
| 219 v8::MicrotasksScope microtasks_scope(isolate(), |
| 220 v8::MicrotasksScope::kRunMicrotasks); |
| 221 v8::HandleScope handle_scope(isolate()); |
| 222 v8::Local<v8::Context> context = data()->GetContext(context_group_id_); |
| 223 v8::Context::Scope context_scope(context); |
| 224 |
| 225 if (dispatchers_.find(session_id_) == dispatchers_.end()) return; |
| 226 v8::Local<v8::Function> function = dispatchers_[session_id_].Get(isolate()); |
| 227 v8::Local<v8::Value> message = |
| 228 v8::String::NewFromTwoByte(isolate(), message_.start(), |
| 229 v8::NewStringType::kNormal, |
| 230 static_cast<int>(message_.size())) |
| 231 .ToLocalChecked(); |
| 232 v8::MaybeLocal<v8::Value> result; |
| 233 result = function->Call(context, context->Global(), 1, &message); |
| 234 } |
| 235 |
| 236 static std::map<int, v8::Global<v8::Function>> dispatchers_; |
| 237 int context_group_id_; |
| 238 int session_id_; |
| 239 v8::internal::Vector<uint16_t> message_; |
| 240 }; |
| 241 |
| 242 std::map<int, v8::Global<v8::Function>> SendMessageToFrontendTask::dispatchers_; |
| 243 |
| 54 class UtilsExtension : public IsolateData::SetupGlobalTask { | 244 class UtilsExtension : public IsolateData::SetupGlobalTask { |
| 55 public: | 245 public: |
| 56 ~UtilsExtension() override = default; | 246 ~UtilsExtension() override = default; |
| 57 void Run(v8::Isolate* isolate, | 247 void Run(v8::Isolate* isolate, |
| 58 v8::Local<v8::ObjectTemplate> global) override { | 248 v8::Local<v8::ObjectTemplate> global) override { |
| 59 v8::Local<v8::ObjectTemplate> utils = v8::ObjectTemplate::New(isolate); | 249 v8::Local<v8::ObjectTemplate> utils = v8::ObjectTemplate::New(isolate); |
| 60 utils->Set(ToV8String(isolate, "print"), | 250 utils->Set(ToV8String(isolate, "print"), |
| 61 v8::FunctionTemplate::New(isolate, &UtilsExtension::Print)); | 251 v8::FunctionTemplate::New(isolate, &UtilsExtension::Print)); |
| 62 utils->Set(ToV8String(isolate, "quit"), | 252 utils->Set(ToV8String(isolate, "quit"), |
| 63 v8::FunctionTemplate::New(isolate, &UtilsExtension::Quit)); | 253 v8::FunctionTemplate::New(isolate, &UtilsExtension::Quit)); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 75 isolate, &UtilsExtension::SetCurrentTimeMSForTest)); | 265 isolate, &UtilsExtension::SetCurrentTimeMSForTest)); |
| 76 utils->Set(ToV8String(isolate, "setMemoryInfoForTest"), | 266 utils->Set(ToV8String(isolate, "setMemoryInfoForTest"), |
| 77 v8::FunctionTemplate::New( | 267 v8::FunctionTemplate::New( |
| 78 isolate, &UtilsExtension::SetMemoryInfoForTest)); | 268 isolate, &UtilsExtension::SetMemoryInfoForTest)); |
| 79 utils->Set(ToV8String(isolate, "schedulePauseOnNextStatement"), | 269 utils->Set(ToV8String(isolate, "schedulePauseOnNextStatement"), |
| 80 v8::FunctionTemplate::New( | 270 v8::FunctionTemplate::New( |
| 81 isolate, &UtilsExtension::SchedulePauseOnNextStatement)); | 271 isolate, &UtilsExtension::SchedulePauseOnNextStatement)); |
| 82 utils->Set(ToV8String(isolate, "cancelPauseOnNextStatement"), | 272 utils->Set(ToV8String(isolate, "cancelPauseOnNextStatement"), |
| 83 v8::FunctionTemplate::New( | 273 v8::FunctionTemplate::New( |
| 84 isolate, &UtilsExtension::CancelPauseOnNextStatement)); | 274 isolate, &UtilsExtension::CancelPauseOnNextStatement)); |
| 85 utils->Set(ToV8String(isolate, "reconnect"), | |
| 86 v8::FunctionTemplate::New(isolate, &UtilsExtension::Reconnect)); | |
| 87 utils->Set(ToV8String(isolate, "disconnect"), | |
| 88 v8::FunctionTemplate::New(isolate, &UtilsExtension::Disconnect)); | |
| 89 utils->Set(ToV8String(isolate, "setLogConsoleApiMessageCalls"), | 275 utils->Set(ToV8String(isolate, "setLogConsoleApiMessageCalls"), |
| 90 v8::FunctionTemplate::New( | 276 v8::FunctionTemplate::New( |
| 91 isolate, &UtilsExtension::SetLogConsoleApiMessageCalls)); | 277 isolate, &UtilsExtension::SetLogConsoleApiMessageCalls)); |
| 92 utils->Set(ToV8String(isolate, "createContextGroup"), | 278 utils->Set(ToV8String(isolate, "createContextGroup"), |
| 93 v8::FunctionTemplate::New(isolate, | 279 v8::FunctionTemplate::New(isolate, |
| 94 &UtilsExtension::CreateContextGroup)); | 280 &UtilsExtension::CreateContextGroup)); |
| 281 utils->Set( |
| 282 ToV8String(isolate, "connectSession"), |
| 283 v8::FunctionTemplate::New(isolate, &UtilsExtension::ConnectSession)); |
| 284 utils->Set( |
| 285 ToV8String(isolate, "disconnectSession"), |
| 286 v8::FunctionTemplate::New(isolate, &UtilsExtension::DisconnectSession)); |
| 287 utils->Set(ToV8String(isolate, "sendMessageToBackend"), |
| 288 v8::FunctionTemplate::New( |
| 289 isolate, &UtilsExtension::SendMessageToBackend)); |
| 95 global->Set(ToV8String(isolate, "utils"), utils); | 290 global->Set(ToV8String(isolate, "utils"), utils); |
| 96 } | 291 } |
| 97 | 292 |
| 98 static void set_backend_task_runner(TaskRunner* runner) { | 293 static void set_backend_task_runner(TaskRunner* runner) { |
| 99 backend_runner_ = runner; | 294 backend_runner_ = runner; |
| 100 } | 295 } |
| 101 | 296 |
| 102 static void set_inspector_client(InspectorClientImpl* client) { | |
| 103 inspector_client_ = client; | |
| 104 } | |
| 105 | |
| 106 private: | 297 private: |
| 107 static TaskRunner* backend_runner_; | 298 static TaskRunner* backend_runner_; |
| 108 static InspectorClientImpl* inspector_client_; | |
| 109 | 299 |
| 110 static void Print(const v8::FunctionCallbackInfo<v8::Value>& args) { | 300 static void Print(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 111 for (int i = 0; i < args.Length(); i++) { | 301 for (int i = 0; i < args.Length(); i++) { |
| 112 v8::HandleScope handle_scope(args.GetIsolate()); | 302 v8::HandleScope handle_scope(args.GetIsolate()); |
| 113 if (i != 0) { | 303 if (i != 0) { |
| 114 printf(" "); | 304 printf(" "); |
| 115 } | 305 } |
| 116 | 306 |
| 117 // Explicitly catch potential exceptions in toString(). | 307 // Explicitly catch potential exceptions in toString(). |
| 118 v8::TryCatch try_catch(args.GetIsolate()); | 308 v8::TryCatch try_catch(args.GetIsolate()); |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 } | 372 } |
| 183 } | 373 } |
| 184 | 374 |
| 185 static void Load(const v8::FunctionCallbackInfo<v8::Value>& args) { | 375 static void Load(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 186 if (args.Length() != 1 || !args[0]->IsString()) { | 376 if (args.Length() != 1 || !args[0]->IsString()) { |
| 187 fprintf(stderr, "Internal error: load gets one string argument."); | 377 fprintf(stderr, "Internal error: load gets one string argument."); |
| 188 Exit(); | 378 Exit(); |
| 189 } | 379 } |
| 190 v8::internal::Vector<const char> chars; | 380 v8::internal::Vector<const char> chars; |
| 191 v8::Isolate* isolate = args.GetIsolate(); | 381 v8::Isolate* isolate = args.GetIsolate(); |
| 382 v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| 383 IsolateData* data = IsolateData::FromContext(context); |
| 384 int context_group_id = data->GetContextGroupId(context); |
| 192 if (ReadFile(isolate, args[0], &chars)) { | 385 if (ReadFile(isolate, args[0], &chars)) { |
| 193 ExecuteStringTask(chars).RunOnTaskRunner( | 386 ExecuteStringTask(chars, context_group_id).RunOnIsolate(data); |
| 194 IsolateData::FromContext(isolate->GetCurrentContext()) | |
| 195 ->task_runner()); | |
| 196 } | 387 } |
| 197 } | 388 } |
| 198 | 389 |
| 199 static void CompileAndRunWithOrigin( | 390 static void CompileAndRunWithOrigin( |
| 200 const v8::FunctionCallbackInfo<v8::Value>& args) { | 391 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 201 if (args.Length() != 5 || !args[0]->IsString() || !args[1]->IsString() || | 392 if (args.Length() != 6 || !args[0]->IsInt32() || !args[1]->IsString() || |
| 202 !args[2]->IsInt32() || !args[3]->IsInt32() || !args[4]->IsBoolean()) { | 393 !args[2]->IsString() || !args[3]->IsInt32() || !args[4]->IsInt32() || |
| 394 !args[5]->IsBoolean()) { |
| 203 fprintf(stderr, | 395 fprintf(stderr, |
| 204 "Internal error: compileAndRunWithOrigin(source, name, line, " | 396 "Internal error: compileAndRunWithOrigin(context_group_id, " |
| 397 "source, name, line, " |
| 205 "column, is_module)."); | 398 "column, is_module)."); |
| 206 Exit(); | 399 Exit(); |
| 207 } | 400 } |
| 208 | 401 |
| 209 backend_runner_->Append(new ExecuteStringTask( | 402 backend_runner_->Append(new ExecuteStringTask( |
| 210 ToVector(args[0].As<v8::String>()), args[1].As<v8::String>(), | 403 nullptr, args[0].As<v8::Int32>()->Value(), nullptr, |
| 211 args[2].As<v8::Int32>(), args[3].As<v8::Int32>(), | 404 ToVector(args[1].As<v8::String>()), args[2].As<v8::String>(), |
| 212 args[4].As<v8::Boolean>(), nullptr, nullptr)); | 405 args[3].As<v8::Int32>(), args[4].As<v8::Int32>(), |
| 406 args[5].As<v8::Boolean>())); |
| 213 } | 407 } |
| 214 | 408 |
| 215 static void SetCurrentTimeMSForTest( | 409 static void SetCurrentTimeMSForTest( |
| 216 const v8::FunctionCallbackInfo<v8::Value>& args) { | 410 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 217 if (args.Length() != 1 || !args[0]->IsNumber()) { | 411 if (args.Length() != 1 || !args[0]->IsNumber()) { |
| 218 fprintf(stderr, "Internal error: setCurrentTimeMSForTest(time)."); | 412 fprintf(stderr, "Internal error: setCurrentTimeMSForTest(time)."); |
| 219 Exit(); | 413 Exit(); |
| 220 } | 414 } |
| 221 inspector_client_->setCurrentTimeMSForTest( | 415 backend_runner_->data()->inspector()->SetCurrentTimeMSForTest( |
| 222 args[0].As<v8::Number>()->Value()); | 416 args[0].As<v8::Number>()->Value()); |
| 223 } | 417 } |
| 224 | 418 |
| 225 static void SetMemoryInfoForTest( | 419 static void SetMemoryInfoForTest( |
| 226 const v8::FunctionCallbackInfo<v8::Value>& args) { | 420 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 227 if (args.Length() != 1) { | 421 if (args.Length() != 1) { |
| 228 fprintf(stderr, "Internal error: setMemoryInfoForTest(value)."); | 422 fprintf(stderr, "Internal error: setMemoryInfoForTest(value)."); |
| 229 Exit(); | 423 Exit(); |
| 230 } | 424 } |
| 231 inspector_client_->setMemoryInfoForTest(args[0]); | 425 backend_runner_->data()->inspector()->SetMemoryInfoForTest(args[0]); |
| 232 } | 426 } |
| 233 | 427 |
| 234 static void SchedulePauseOnNextStatement( | 428 static void SchedulePauseOnNextStatement( |
| 235 const v8::FunctionCallbackInfo<v8::Value>& args) { | 429 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 236 if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) { | 430 if (args.Length() != 3 || !args[0]->IsInt32() || !args[1]->IsString() || |
| 237 fprintf( | 431 !args[2]->IsString()) { |
| 238 stderr, | 432 fprintf(stderr, |
| 239 "Internal error: schedulePauseOnNextStatement('reason', 'details')."); | 433 "Internal error: schedulePauseOnNextStatement(context_group_id, " |
| 434 "'reason', 'details')."); |
| 240 Exit(); | 435 Exit(); |
| 241 } | 436 } |
| 242 v8::internal::Vector<uint16_t> reason = ToVector(args[0].As<v8::String>()); | 437 v8::internal::Vector<uint16_t> reason = ToVector(args[1].As<v8::String>()); |
| 243 v8_inspector::StringView reason_view(reason.start(), reason.length()); | 438 v8::internal::Vector<uint16_t> details = ToVector(args[2].As<v8::String>()); |
| 244 v8::internal::Vector<uint16_t> details = ToVector(args[1].As<v8::String>()); | 439 v8::base::Semaphore ready_semaphore(0); |
| 245 v8_inspector::StringView details_view(details.start(), details.length()); | 440 backend_runner_->Append(new SchedulePauseOnNextStatementTask( |
| 246 inspector_client_->session()->schedulePauseOnNextStatement(reason_view, | 441 &ready_semaphore, args[0].As<v8::Int32>()->Value(), reason, details)); |
| 247 details_view); | 442 ready_semaphore.Wait(); |
| 248 } | 443 } |
| 249 | 444 |
| 250 static void CancelPauseOnNextStatement( | 445 static void CancelPauseOnNextStatement( |
| 251 const v8::FunctionCallbackInfo<v8::Value>& args) { | 446 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 252 if (args.Length() != 0) { | 447 if (args.Length() != 1 || !args[0]->IsInt32()) { |
| 253 fprintf(stderr, "Internal error: cancelPauseOnNextStatement()."); | 448 fprintf(stderr, |
| 254 Exit(); | 449 "Internal error: cancelPauseOnNextStatement(context_group_id)."); |
| 255 } | |
| 256 inspector_client_->session()->cancelPauseOnNextStatement(); | |
| 257 } | |
| 258 | |
| 259 static void Reconnect(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 260 if (args.Length() != 0) { | |
| 261 fprintf(stderr, "Internal error: reconnect()."); | |
| 262 Exit(); | 450 Exit(); |
| 263 } | 451 } |
| 264 v8::base::Semaphore ready_semaphore(0); | 452 v8::base::Semaphore ready_semaphore(0); |
| 265 inspector_client_->scheduleReconnect(&ready_semaphore); | 453 backend_runner_->Append(new CancelPauseOnNextStatementTask( |
| 266 ready_semaphore.Wait(); | 454 &ready_semaphore, args[0].As<v8::Int32>()->Value())); |
| 267 } | |
| 268 | |
| 269 static void Disconnect(const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 270 if (args.Length() != 0) { | |
| 271 fprintf(stderr, "Internal error: disconnect()."); | |
| 272 Exit(); | |
| 273 } | |
| 274 v8::base::Semaphore ready_semaphore(0); | |
| 275 inspector_client_->scheduleDisconnect(&ready_semaphore); | |
| 276 ready_semaphore.Wait(); | 455 ready_semaphore.Wait(); |
| 277 } | 456 } |
| 278 | 457 |
| 279 static void SetLogConsoleApiMessageCalls( | 458 static void SetLogConsoleApiMessageCalls( |
| 280 const v8::FunctionCallbackInfo<v8::Value>& args) { | 459 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 281 if (args.Length() != 1 || !args[0]->IsBoolean()) { | 460 if (args.Length() != 1 || !args[0]->IsBoolean()) { |
| 282 fprintf(stderr, "Internal error: setLogConsoleApiMessageCalls(bool)."); | 461 fprintf(stderr, "Internal error: setLogConsoleApiMessageCalls(bool)."); |
| 283 Exit(); | 462 Exit(); |
| 284 } | 463 } |
| 285 inspector_client_->setLogConsoleApiMessageCalls( | 464 backend_runner_->data()->inspector()->SetLogConsoleApiMessageCalls( |
| 286 args[0].As<v8::Boolean>()->Value()); | 465 args[0].As<v8::Boolean>()->Value()); |
| 287 } | 466 } |
| 288 | 467 |
| 289 static void CreateContextGroup( | 468 static void CreateContextGroup( |
| 290 const v8::FunctionCallbackInfo<v8::Value>& args); | 469 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 470 if (args.Length() != 0) { |
| 471 fprintf(stderr, "Internal error: createContextGroup()."); |
| 472 Exit(); |
| 473 } |
| 474 v8::base::Semaphore ready_semaphore(0); |
| 475 int context_group_id = 0; |
| 476 backend_runner_->Append( |
| 477 new CreateContextGroupTask(&ready_semaphore, &context_group_id)); |
| 478 ready_semaphore.Wait(); |
| 479 args.GetReturnValue().Set( |
| 480 v8::Int32::New(args.GetIsolate(), context_group_id)); |
| 481 } |
| 482 |
| 483 static void ConnectSession(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 484 if (args.Length() != 3 || !args[0]->IsInt32() || !args[1]->IsString() || |
| 485 !args[2]->IsFunction()) { |
| 486 fprintf(stderr, |
| 487 "Internal error: connectionSession(context_group_id, state, " |
| 488 "dispatch)."); |
| 489 Exit(); |
| 490 } |
| 491 v8::internal::Vector<uint16_t> state = ToVector(args[1].As<v8::String>()); |
| 492 v8::base::Semaphore ready_semaphore(0); |
| 493 int session_id = 0; |
| 494 backend_runner_->Append(new ConnectSessionTask( |
| 495 &ready_semaphore, args[0].As<v8::Int32>()->Value(), state, |
| 496 &session_id)); |
| 497 ready_semaphore.Wait(); |
| 498 SendMessageToFrontendTask::Register(session_id, args.GetIsolate(), |
| 499 args[2].As<v8::Function>()); |
| 500 args.GetReturnValue().Set(v8::Int32::New(args.GetIsolate(), session_id)); |
| 501 } |
| 502 |
| 503 static void DisconnectSession( |
| 504 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 505 if (args.Length() != 1 || !args[0]->IsInt32()) { |
| 506 fprintf(stderr, "Internal error: disconnectionSession(session_id)."); |
| 507 Exit(); |
| 508 } |
| 509 int session_id = args[0].As<v8::Int32>()->Value(); |
| 510 SendMessageToFrontendTask::Unregister(session_id); |
| 511 v8::base::Semaphore ready_semaphore(0); |
| 512 v8::internal::Vector<uint16_t> state; |
| 513 backend_runner_->Append( |
| 514 new DisconnectSessionTask(&ready_semaphore, session_id, &state)); |
| 515 ready_semaphore.Wait(); |
| 516 args.GetReturnValue().Set( |
| 517 v8::String::NewFromTwoByte(args.GetIsolate(), state.start(), |
| 518 v8::NewStringType::kNormal, |
| 519 static_cast<int>(state.size())) |
| 520 .ToLocalChecked()); |
| 521 } |
| 522 |
| 523 static void SendMessageToBackend( |
| 524 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 525 if (args.Length() != 2 || !args[0]->IsInt32() || !args[1]->IsString()) { |
| 526 fprintf(stderr, |
| 527 "Internal error: sendMessageToBackend(session_id, message)."); |
| 528 Exit(); |
| 529 } |
| 530 backend_runner_->Append(new SendMessageToBackendTask( |
| 531 args[0].As<v8::Int32>()->Value(), ToVector(args[1].As<v8::String>()))); |
| 532 } |
| 291 }; | 533 }; |
| 292 | 534 |
| 293 TaskRunner* UtilsExtension::backend_runner_ = nullptr; | 535 TaskRunner* UtilsExtension::backend_runner_ = nullptr; |
| 294 InspectorClientImpl* UtilsExtension::inspector_client_ = nullptr; | |
| 295 | 536 |
| 296 class SetTimeoutTask : public AsyncTask { | 537 class SetTimeoutTask : public AsyncTask { |
| 297 public: | 538 public: |
| 298 SetTimeoutTask(v8::Isolate* isolate, v8::Local<v8::Function> function, | 539 SetTimeoutTask(IsolateData* data, int context_group_id, const char* task_name, |
| 299 const char* task_name, v8_inspector::V8Inspector* inspector) | 540 v8::Local<v8::Function> function) |
| 300 : AsyncTask(task_name, inspector), function_(isolate, function) {} | 541 : AsyncTask(data, task_name), |
| 542 function_(data->isolate(), function), |
| 543 context_group_id_(context_group_id) {} |
| 301 virtual ~SetTimeoutTask() {} | 544 virtual ~SetTimeoutTask() {} |
| 302 | 545 |
| 303 bool is_inspector_task() final { return false; } | 546 bool is_inspector_task() final { return false; } |
| 304 | 547 |
| 305 private: | 548 private: |
| 306 void AsyncRun() override { | 549 void AsyncRun() override { |
| 307 v8::MicrotasksScope microtasks_scope(isolate(), | 550 v8::MicrotasksScope microtasks_scope(isolate(), |
| 308 v8::MicrotasksScope::kRunMicrotasks); | 551 v8::MicrotasksScope::kRunMicrotasks); |
| 309 v8::HandleScope handle_scope(isolate()); | 552 v8::HandleScope handle_scope(isolate()); |
| 310 v8::Local<v8::Context> context = default_context(); | 553 v8::Local<v8::Context> context = data()->GetContext(context_group_id_); |
| 311 v8::Context::Scope context_scope(context); | 554 v8::Context::Scope context_scope(context); |
| 312 | 555 |
| 313 v8::Local<v8::Function> function = function_.Get(isolate()); | 556 v8::Local<v8::Function> function = function_.Get(isolate()); |
| 314 v8::MaybeLocal<v8::Value> result; | 557 v8::MaybeLocal<v8::Value> result; |
| 315 result = function->Call(context, context->Global(), 0, nullptr); | 558 result = function->Call(context, context->Global(), 0, nullptr); |
| 316 } | 559 } |
| 317 | 560 |
| 318 v8::Global<v8::Function> function_; | 561 v8::Global<v8::Function> function_; |
| 562 int context_group_id_; |
| 319 }; | 563 }; |
| 320 | 564 |
| 321 class SetTimeoutExtension : public IsolateData::SetupGlobalTask { | 565 class SetTimeoutExtension : public IsolateData::SetupGlobalTask { |
| 322 public: | 566 public: |
| 323 void Run(v8::Isolate* isolate, | 567 void Run(v8::Isolate* isolate, |
| 324 v8::Local<v8::ObjectTemplate> global) override { | 568 v8::Local<v8::ObjectTemplate> global) override { |
| 325 global->Set( | 569 global->Set( |
| 326 ToV8String(isolate, "setTimeout"), | 570 ToV8String(isolate, "setTimeout"), |
| 327 v8::FunctionTemplate::New(isolate, &SetTimeoutExtension::SetTimeout)); | 571 v8::FunctionTemplate::New(isolate, &SetTimeoutExtension::SetTimeout)); |
| 328 } | 572 } |
| 329 | 573 |
| 330 private: | 574 private: |
| 331 static void SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args) { | 575 static void SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 332 if (args.Length() != 2 || !args[1]->IsNumber() || | 576 if (args.Length() != 2 || !args[1]->IsNumber() || |
| 333 (!args[0]->IsFunction() && !args[0]->IsString()) || | 577 (!args[0]->IsFunction() && !args[0]->IsString()) || |
| 334 args[1].As<v8::Number>()->Value() != 0.0) { | 578 args[1].As<v8::Number>()->Value() != 0.0) { |
| 335 fprintf(stderr, | 579 fprintf( |
| 336 "Internal error: only setTimeout(function, 0) is supported."); | 580 stderr, |
| 581 "Internal error: only setTimeout(function|code, 0) is supported."); |
| 337 Exit(); | 582 Exit(); |
| 338 } | 583 } |
| 339 v8::Isolate* isolate = args.GetIsolate(); | 584 v8::Isolate* isolate = args.GetIsolate(); |
| 340 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | 585 v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| 586 IsolateData* data = IsolateData::FromContext(context); |
| 587 int context_group_id = data->GetContextGroupId(context); |
| 341 std::unique_ptr<TaskRunner::Task> task; | 588 std::unique_ptr<TaskRunner::Task> task; |
| 342 v8_inspector::V8Inspector* inspector = | |
| 343 InspectorClientImpl::InspectorFromContext(context); | |
| 344 if (args[0]->IsFunction()) { | 589 if (args[0]->IsFunction()) { |
| 345 task.reset(new SetTimeoutTask(isolate, | 590 task.reset(new SetTimeoutTask(data, context_group_id, "setTimeout", |
| 346 v8::Local<v8::Function>::Cast(args[0]), | 591 v8::Local<v8::Function>::Cast(args[0]))); |
| 347 "setTimeout", inspector)); | |
| 348 } else { | 592 } else { |
| 349 task.reset(new ExecuteStringTask( | 593 task.reset(new ExecuteStringTask( |
| 594 data, context_group_id, "setTimeout", |
| 350 ToVector(args[0].As<v8::String>()), v8::String::Empty(isolate), | 595 ToVector(args[0].As<v8::String>()), v8::String::Empty(isolate), |
| 351 v8::Integer::New(isolate, 0), v8::Integer::New(isolate, 0), | 596 v8::Integer::New(isolate, 0), v8::Integer::New(isolate, 0), |
| 352 v8::Boolean::New(isolate, false), "setTimeout", inspector)); | 597 v8::Boolean::New(isolate, false))); |
| 353 } | 598 } |
| 354 IsolateData::FromContext(context)->task_runner()->Append(task.release()); | 599 data->task_runner()->Append(task.release()); |
| 355 } | 600 } |
| 356 }; | 601 }; |
| 357 | 602 |
| 358 bool StrictAccessCheck(v8::Local<v8::Context> accessing_context, | 603 bool StrictAccessCheck(v8::Local<v8::Context> accessing_context, |
| 359 v8::Local<v8::Object> accessed_object, | 604 v8::Local<v8::Object> accessed_object, |
| 360 v8::Local<v8::Value> data) { | 605 v8::Local<v8::Value> data) { |
| 361 CHECK(accessing_context.IsEmpty()); | 606 CHECK(accessing_context.IsEmpty()); |
| 362 return accessing_context.IsEmpty(); | 607 return accessing_context.IsEmpty(); |
| 363 } | 608 } |
| 364 | 609 |
| 365 class InspectorExtension : public IsolateData::SetupGlobalTask { | 610 class InspectorExtension : public IsolateData::SetupGlobalTask { |
| 366 public: | 611 public: |
| 367 ~InspectorExtension() override = default; | 612 ~InspectorExtension() override = default; |
| 368 void Run(v8::Isolate* isolate, | 613 void Run(v8::Isolate* isolate, |
| 369 v8::Local<v8::ObjectTemplate> global) override { | 614 v8::Local<v8::ObjectTemplate> global) override { |
| 370 v8::Local<v8::ObjectTemplate> inspector = v8::ObjectTemplate::New(isolate); | 615 v8::Local<v8::ObjectTemplate> inspector = v8::ObjectTemplate::New(isolate); |
| 371 inspector->Set( | 616 inspector->Set(ToV8String(isolate, "fireContextCreated"), |
| 372 ToV8String(isolate, "attachInspector"), | 617 v8::FunctionTemplate::New( |
| 373 v8::FunctionTemplate::New(isolate, &InspectorExtension::Attach)); | 618 isolate, &InspectorExtension::FireContextCreated)); |
| 374 inspector->Set( | 619 inspector->Set(ToV8String(isolate, "fireContextDestroyed"), |
| 375 ToV8String(isolate, "detachInspector"), | 620 v8::FunctionTemplate::New( |
| 376 v8::FunctionTemplate::New(isolate, &InspectorExtension::Detach)); | 621 isolate, &InspectorExtension::FireContextDestroyed)); |
| 377 inspector->Set(ToV8String(isolate, "setMaxAsyncTaskStacks"), | 622 inspector->Set(ToV8String(isolate, "setMaxAsyncTaskStacks"), |
| 378 v8::FunctionTemplate::New( | 623 v8::FunctionTemplate::New( |
| 379 isolate, &InspectorExtension::SetMaxAsyncTaskStacks)); | 624 isolate, &InspectorExtension::SetMaxAsyncTaskStacks)); |
| 380 inspector->Set( | 625 inspector->Set( |
| 381 ToV8String(isolate, "dumpAsyncTaskStacksStateForTest"), | 626 ToV8String(isolate, "dumpAsyncTaskStacksStateForTest"), |
| 382 v8::FunctionTemplate::New( | 627 v8::FunctionTemplate::New( |
| 383 isolate, &InspectorExtension::DumpAsyncTaskStacksStateForTest)); | 628 isolate, &InspectorExtension::DumpAsyncTaskStacksStateForTest)); |
| 384 inspector->Set( | 629 inspector->Set( |
| 385 ToV8String(isolate, "breakProgram"), | 630 ToV8String(isolate, "breakProgram"), |
| 386 v8::FunctionTemplate::New(isolate, &InspectorExtension::BreakProgram)); | 631 v8::FunctionTemplate::New(isolate, &InspectorExtension::BreakProgram)); |
| 387 inspector->Set( | 632 inspector->Set( |
| 388 ToV8String(isolate, "createObjectWithStrictCheck"), | 633 ToV8String(isolate, "createObjectWithStrictCheck"), |
| 389 v8::FunctionTemplate::New( | 634 v8::FunctionTemplate::New( |
| 390 isolate, &InspectorExtension::CreateObjectWithStrictCheck)); | 635 isolate, &InspectorExtension::CreateObjectWithStrictCheck)); |
| 391 inspector->Set(ToV8String(isolate, "callWithScheduledBreak"), | 636 inspector->Set(ToV8String(isolate, "callWithScheduledBreak"), |
| 392 v8::FunctionTemplate::New( | 637 v8::FunctionTemplate::New( |
| 393 isolate, &InspectorExtension::CallWithScheduledBreak)); | 638 isolate, &InspectorExtension::CallWithScheduledBreak)); |
| 394 inspector->Set(ToV8String(isolate, "allowAccessorFormatting"), | 639 inspector->Set(ToV8String(isolate, "allowAccessorFormatting"), |
| 395 v8::FunctionTemplate::New( | 640 v8::FunctionTemplate::New( |
| 396 isolate, &InspectorExtension::AllowAccessorFormatting)); | 641 isolate, &InspectorExtension::AllowAccessorFormatting)); |
| 397 global->Set(ToV8String(isolate, "inspector"), inspector); | 642 global->Set(ToV8String(isolate, "inspector"), inspector); |
| 398 } | 643 } |
| 399 | 644 |
| 400 private: | 645 private: |
| 401 static void Attach(const v8::FunctionCallbackInfo<v8::Value>& args) { | 646 static void FireContextCreated( |
| 402 v8::Isolate* isolate = args.GetIsolate(); | 647 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 403 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | 648 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); |
| 404 v8_inspector::V8Inspector* inspector = | 649 IsolateData* data = IsolateData::FromContext(context); |
| 405 InspectorClientImpl::InspectorFromContext(context); | 650 data->inspector()->ContextCreated(context, |
| 406 if (!inspector) { | 651 data->GetContextGroupId(context)); |
| 407 fprintf(stderr, "Inspector client not found - cannot attach!"); | |
| 408 Exit(); | |
| 409 } | |
| 410 inspector->contextCreated( | |
| 411 v8_inspector::V8ContextInfo(context, 1, v8_inspector::StringView())); | |
| 412 } | 652 } |
| 413 | 653 |
| 414 static void Detach(const v8::FunctionCallbackInfo<v8::Value>& args) { | 654 static void FireContextDestroyed( |
| 415 v8::Isolate* isolate = args.GetIsolate(); | 655 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 416 v8::Local<v8::Context> context = isolate->GetCurrentContext(); | 656 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); |
| 417 v8_inspector::V8Inspector* inspector = | 657 IsolateData* data = IsolateData::FromContext(context); |
| 418 InspectorClientImpl::InspectorFromContext(context); | 658 data->inspector()->ContextDestroyed(context); |
| 419 if (!inspector) { | |
| 420 fprintf(stderr, "Inspector client not found - cannot detach!"); | |
| 421 Exit(); | |
| 422 } | |
| 423 inspector->contextDestroyed(context); | |
| 424 } | 659 } |
| 425 | 660 |
| 426 static void SetMaxAsyncTaskStacks( | 661 static void SetMaxAsyncTaskStacks( |
| 427 const v8::FunctionCallbackInfo<v8::Value>& args) { | 662 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 428 if (args.Length() != 1 || !args[0]->IsInt32()) { | 663 if (args.Length() != 1 || !args[0]->IsInt32()) { |
| 429 fprintf(stderr, "Internal error: setMaxAsyncTaskStacks(max)."); | 664 fprintf(stderr, "Internal error: setMaxAsyncTaskStacks(max)."); |
| 430 Exit(); | 665 Exit(); |
| 431 } | 666 } |
| 432 v8_inspector::V8Inspector* inspector = | |
| 433 InspectorClientImpl::InspectorFromContext( | |
| 434 args.GetIsolate()->GetCurrentContext()); | |
| 435 CHECK(inspector); | |
| 436 v8_inspector::SetMaxAsyncTaskStacksForTest( | 667 v8_inspector::SetMaxAsyncTaskStacksForTest( |
| 437 inspector, args[0].As<v8::Int32>()->Value()); | 668 IsolateData::FromContext(args.GetIsolate()->GetCurrentContext()) |
| 669 ->inspector() |
| 670 ->inspector(), |
| 671 args[0].As<v8::Int32>()->Value()); |
| 438 } | 672 } |
| 439 | 673 |
| 440 static void DumpAsyncTaskStacksStateForTest( | 674 static void DumpAsyncTaskStacksStateForTest( |
| 441 const v8::FunctionCallbackInfo<v8::Value>& args) { | 675 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 442 if (args.Length() != 0) { | 676 if (args.Length() != 0) { |
| 443 fprintf(stderr, "Internal error: dumpAsyncTaskStacksStateForTest()."); | 677 fprintf(stderr, "Internal error: dumpAsyncTaskStacksStateForTest()."); |
| 444 Exit(); | 678 Exit(); |
| 445 } | 679 } |
| 446 v8_inspector::V8Inspector* inspector = | 680 v8_inspector::DumpAsyncTaskStacksStateForTest( |
| 447 InspectorClientImpl::InspectorFromContext( | 681 IsolateData::FromContext(args.GetIsolate()->GetCurrentContext()) |
| 448 args.GetIsolate()->GetCurrentContext()); | 682 ->inspector() |
| 449 CHECK(inspector); | 683 ->inspector()); |
| 450 v8_inspector::DumpAsyncTaskStacksStateForTest(inspector); | |
| 451 } | 684 } |
| 452 | 685 |
| 453 static void BreakProgram(const v8::FunctionCallbackInfo<v8::Value>& args) { | 686 static void BreakProgram(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 454 if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) { | 687 if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) { |
| 455 fprintf(stderr, "Internal error: breakProgram('reason', 'details')."); | 688 fprintf(stderr, "Internal error: breakProgram('reason', 'details')."); |
| 456 Exit(); | 689 Exit(); |
| 457 } | 690 } |
| 458 v8_inspector::V8InspectorSession* session = | 691 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); |
| 459 InspectorClientImpl::SessionFromContext( | 692 IsolateData* data = IsolateData::FromContext(context); |
| 460 args.GetIsolate()->GetCurrentContext()); | |
| 461 CHECK(session); | |
| 462 | |
| 463 v8::internal::Vector<uint16_t> reason = ToVector(args[0].As<v8::String>()); | 693 v8::internal::Vector<uint16_t> reason = ToVector(args[0].As<v8::String>()); |
| 464 v8_inspector::StringView reason_view(reason.start(), reason.length()); | 694 v8_inspector::StringView reason_view(reason.start(), reason.length()); |
| 465 v8::internal::Vector<uint16_t> details = ToVector(args[1].As<v8::String>()); | 695 v8::internal::Vector<uint16_t> details = ToVector(args[1].As<v8::String>()); |
| 466 v8_inspector::StringView details_view(details.start(), details.length()); | 696 v8_inspector::StringView details_view(details.start(), details.length()); |
| 467 session->breakProgram(reason_view, details_view); | 697 data->inspector()->BreakProgram(data->GetContextGroupId(context), |
| 698 reason_view, details_view); |
| 468 } | 699 } |
| 469 | 700 |
| 470 static void CreateObjectWithStrictCheck( | 701 static void CreateObjectWithStrictCheck( |
| 471 const v8::FunctionCallbackInfo<v8::Value>& args) { | 702 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 472 if (args.Length() != 0) { | 703 if (args.Length() != 0) { |
| 473 fprintf(stderr, "Internal error: createObjectWithStrictCheck()."); | 704 fprintf(stderr, "Internal error: createObjectWithStrictCheck()."); |
| 474 Exit(); | 705 Exit(); |
| 475 } | 706 } |
| 476 v8::Local<v8::ObjectTemplate> templ = | 707 v8::Local<v8::ObjectTemplate> templ = |
| 477 v8::ObjectTemplate::New(args.GetIsolate()); | 708 v8::ObjectTemplate::New(args.GetIsolate()); |
| 478 templ->SetAccessCheckCallback(&StrictAccessCheck); | 709 templ->SetAccessCheckCallback(&StrictAccessCheck); |
| 479 args.GetReturnValue().Set( | 710 args.GetReturnValue().Set( |
| 480 templ->NewInstance(args.GetIsolate()->GetCurrentContext()) | 711 templ->NewInstance(args.GetIsolate()->GetCurrentContext()) |
| 481 .ToLocalChecked()); | 712 .ToLocalChecked()); |
| 482 } | 713 } |
| 483 | 714 |
| 484 static void CallWithScheduledBreak( | 715 static void CallWithScheduledBreak( |
| 485 const v8::FunctionCallbackInfo<v8::Value>& args) { | 716 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 486 if (args.Length() != 3 || !args[0]->IsFunction() || !args[1]->IsString() || | 717 if (args.Length() != 3 || !args[0]->IsFunction() || !args[1]->IsString() || |
| 487 !args[2]->IsString()) { | 718 !args[2]->IsString()) { |
| 488 fprintf(stderr, "Internal error: breakProgram('reason', 'details')."); | 719 fprintf(stderr, |
| 720 "Internal error: callWithScheduledBreak('reason', 'details')."); |
| 489 Exit(); | 721 Exit(); |
| 490 } | 722 } |
| 491 v8_inspector::V8InspectorSession* session = | |
| 492 InspectorClientImpl::SessionFromContext( | |
| 493 args.GetIsolate()->GetCurrentContext()); | |
| 494 CHECK(session); | |
| 495 | |
| 496 v8::internal::Vector<uint16_t> reason = ToVector(args[1].As<v8::String>()); | 723 v8::internal::Vector<uint16_t> reason = ToVector(args[1].As<v8::String>()); |
| 497 v8_inspector::StringView reason_view(reason.start(), reason.length()); | 724 v8_inspector::StringView reason_view(reason.start(), reason.length()); |
| 498 v8::internal::Vector<uint16_t> details = ToVector(args[2].As<v8::String>()); | 725 v8::internal::Vector<uint16_t> details = ToVector(args[2].As<v8::String>()); |
| 499 v8_inspector::StringView details_view(details.start(), details.length()); | 726 v8_inspector::StringView details_view(details.start(), details.length()); |
| 500 session->schedulePauseOnNextStatement(reason_view, details_view); | |
| 501 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); | 727 v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext(); |
| 728 IsolateData* data = IsolateData::FromContext(context); |
| 729 int context_group_id = data->GetContextGroupId(context); |
| 730 data->inspector()->SchedulePauseOnNextStatement(context_group_id, |
| 731 reason_view, details_view); |
| 502 v8::MaybeLocal<v8::Value> result; | 732 v8::MaybeLocal<v8::Value> result; |
| 503 result = args[0].As<v8::Function>()->Call(context, context->Global(), 0, | 733 result = args[0].As<v8::Function>()->Call(context, context->Global(), 0, |
| 504 nullptr); | 734 nullptr); |
| 505 session->cancelPauseOnNextStatement(); | 735 data->inspector()->CancelPauseOnNextStatement(context_group_id); |
| 506 } | 736 } |
| 507 | 737 |
| 508 static void AllowAccessorFormatting( | 738 static void AllowAccessorFormatting( |
| 509 const v8::FunctionCallbackInfo<v8::Value>& args) { | 739 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 510 if (args.Length() != 1 || !args[0]->IsObject()) { | 740 if (args.Length() != 1 || !args[0]->IsObject()) { |
| 511 fprintf(stderr, "Internal error: allowAccessorFormatting('object')."); | 741 fprintf(stderr, "Internal error: allowAccessorFormatting('object')."); |
| 512 Exit(); | 742 Exit(); |
| 513 } | 743 } |
| 514 v8::Local<v8::Object> object = args[0].As<v8::Object>(); | 744 v8::Local<v8::Object> object = args[0].As<v8::Object>(); |
| 515 v8::Isolate* isolate = args.GetIsolate(); | 745 v8::Isolate* isolate = args.GetIsolate(); |
| 516 v8::Local<v8::Private> shouldFormatAccessorsPrivate = v8::Private::ForApi( | 746 v8::Local<v8::Private> shouldFormatAccessorsPrivate = v8::Private::ForApi( |
| 517 isolate, v8::String::NewFromUtf8(isolate, "allowAccessorFormatting", | 747 isolate, v8::String::NewFromUtf8(isolate, "allowAccessorFormatting", |
| 518 v8::NewStringType::kNormal) | 748 v8::NewStringType::kNormal) |
| 519 .ToLocalChecked()); | 749 .ToLocalChecked()); |
| 520 object | 750 object |
| 521 ->SetPrivate(isolate->GetCurrentContext(), shouldFormatAccessorsPrivate, | 751 ->SetPrivate(isolate->GetCurrentContext(), shouldFormatAccessorsPrivate, |
| 522 v8::Null(isolate)) | 752 v8::Null(isolate)) |
| 523 .ToChecked(); | 753 .ToChecked(); |
| 524 } | 754 } |
| 525 }; | 755 }; |
| 526 | 756 |
| 527 void UtilsExtension::CreateContextGroup( | |
| 528 const v8::FunctionCallbackInfo<v8::Value>& args) { | |
| 529 if (args.Length() != 0) { | |
| 530 fprintf(stderr, "Internal error: createContextGroup()."); | |
| 531 Exit(); | |
| 532 } | |
| 533 v8::base::Semaphore ready_semaphore(0); | |
| 534 int context_group_id = 0; | |
| 535 IsolateData::SetupGlobalTasks setup_global; | |
| 536 setup_global.emplace_back(new SetTimeoutExtension()); | |
| 537 setup_global.emplace_back(new InspectorExtension()); | |
| 538 inspector_client_->scheduleCreateContextGroup( | |
| 539 std::move(setup_global), &ready_semaphore, &context_group_id); | |
| 540 ready_semaphore.Wait(); | |
| 541 args.GetReturnValue().Set( | |
| 542 v8::Int32::New(args.GetIsolate(), context_group_id)); | |
| 543 } | |
| 544 | |
| 545 v8::Local<v8::String> ToString(v8::Isolate* isolate, | |
| 546 const v8_inspector::StringView& string) { | |
| 547 if (string.is8Bit()) | |
| 548 return v8::String::NewFromOneByte(isolate, string.characters8(), | |
| 549 v8::NewStringType::kNormal, | |
| 550 static_cast<int>(string.length())) | |
| 551 .ToLocalChecked(); | |
| 552 else | |
| 553 return v8::String::NewFromTwoByte(isolate, string.characters16(), | |
| 554 v8::NewStringType::kNormal, | |
| 555 static_cast<int>(string.length())) | |
| 556 .ToLocalChecked(); | |
| 557 } | |
| 558 | |
| 559 class FrontendChannelImpl : public InspectorClientImpl::FrontendChannel { | 757 class FrontendChannelImpl : public InspectorClientImpl::FrontendChannel { |
| 560 public: | 758 public: |
| 561 explicit FrontendChannelImpl(TaskRunner* frontend_task_runner) | 759 FrontendChannelImpl(TaskRunner* frontend_task_runner, int context_group_id) |
| 562 : frontend_task_runner_(frontend_task_runner) {} | 760 : frontend_task_runner_(frontend_task_runner), |
| 761 context_group_id_(context_group_id) {} |
| 563 virtual ~FrontendChannelImpl() {} | 762 virtual ~FrontendChannelImpl() {} |
| 564 | 763 |
| 565 void SendMessageToFrontend(const v8_inspector::StringView& message) final { | 764 void SendMessageToFrontend(int session_id, |
| 566 v8::Isolate* isolate = v8::Isolate::GetCurrent(); | 765 const v8_inspector::StringView& message) final { |
| 567 v8::HandleScope scope(v8::Isolate::GetCurrent()); | 766 frontend_task_runner_->Append(new SendMessageToFrontendTask( |
| 568 | 767 context_group_id_, session_id, ToVector(message))); |
| 569 v8::Local<v8::String> prefix = | |
| 570 v8::String::NewFromUtf8(isolate, "InspectorTest._dispatchMessage(", | |
| 571 v8::NewStringType::kInternalized) | |
| 572 .ToLocalChecked(); | |
| 573 v8::Local<v8::String> message_string = ToString(isolate, message); | |
| 574 v8::Local<v8::String> suffix = | |
| 575 v8::String::NewFromUtf8(isolate, ")", v8::NewStringType::kInternalized) | |
| 576 .ToLocalChecked(); | |
| 577 | |
| 578 v8::Local<v8::String> result = v8::String::Concat(prefix, message_string); | |
| 579 result = v8::String::Concat(result, suffix); | |
| 580 | |
| 581 frontend_task_runner_->Append(new ExecuteStringTask( | |
| 582 ToVector(result), v8::String::Empty(isolate), | |
| 583 v8::Integer::New(isolate, 0), v8::Integer::New(isolate, 0), | |
| 584 v8::Boolean::New(isolate, false), nullptr, nullptr)); | |
| 585 } | 768 } |
| 586 | 769 |
| 587 private: | 770 private: |
| 588 TaskRunner* frontend_task_runner_; | 771 TaskRunner* frontend_task_runner_; |
| 772 int context_group_id_; |
| 589 }; | 773 }; |
| 590 | 774 |
| 591 } // namespace | 775 } // namespace |
| 592 | 776 |
| 593 int main(int argc, char* argv[]) { | 777 int main(int argc, char* argv[]) { |
| 594 v8::V8::InitializeICUDefaultLocation(argv[0]); | 778 v8::V8::InitializeICUDefaultLocation(argv[0]); |
| 595 v8::Platform* platform = v8::platform::CreateDefaultPlatform(); | 779 v8::Platform* platform = v8::platform::CreateDefaultPlatform(); |
| 596 v8::V8::InitializePlatform(platform); | 780 v8::V8::InitializePlatform(platform); |
| 597 v8::V8::SetFlagsFromCommandLine(&argc, argv, true); | 781 v8::V8::SetFlagsFromCommandLine(&argc, argv, true); |
| 598 v8::V8::InitializeExternalStartupData(argv[0]); | 782 v8::V8::InitializeExternalStartupData(argv[0]); |
| 599 v8::V8::Initialize(); | 783 v8::V8::Initialize(); |
| 600 | 784 |
| 601 v8::base::Semaphore ready_semaphore(0); | 785 v8::base::Semaphore ready_semaphore(0); |
| 602 | 786 |
| 603 v8::StartupData startup_data = {nullptr, 0}; | 787 v8::StartupData startup_data = {nullptr, 0}; |
| 604 for (int i = 1; i < argc; ++i) { | 788 for (int i = 1; i < argc; ++i) { |
| 605 if (strcmp(argv[i], "--embed") == 0) { | 789 if (strcmp(argv[i], "--embed") == 0) { |
| 606 argv[i++] = nullptr; | 790 argv[i++] = nullptr; |
| 607 printf("Embedding script '%s'\n", argv[i]); | 791 printf("Embedding script '%s'\n", argv[i]); |
| 608 startup_data = v8::V8::CreateSnapshotDataBlob(argv[i]); | 792 startup_data = v8::V8::CreateSnapshotDataBlob(argv[i]); |
| 609 argv[i] = nullptr; | 793 argv[i] = nullptr; |
| 610 } | 794 } |
| 611 } | 795 } |
| 612 | 796 |
| 797 IsolateData::SetupGlobalTasks frontend_extensions; |
| 798 frontend_extensions.emplace_back(new UtilsExtension()); |
| 799 TaskRunner frontend_runner(std::move(frontend_extensions), true, |
| 800 &ready_semaphore, nullptr, nullptr); |
| 801 ready_semaphore.Wait(); |
| 802 |
| 803 int frontend_context_group_id = 0; |
| 804 frontend_runner.Append( |
| 805 new CreateContextGroupTask(&ready_semaphore, &frontend_context_group_id)); |
| 806 ready_semaphore.Wait(); |
| 807 |
| 613 IsolateData::SetupGlobalTasks backend_extensions; | 808 IsolateData::SetupGlobalTasks backend_extensions; |
| 614 backend_extensions.emplace_back(new SetTimeoutExtension()); | 809 backend_extensions.emplace_back(new SetTimeoutExtension()); |
| 615 backend_extensions.emplace_back(new InspectorExtension()); | 810 backend_extensions.emplace_back(new InspectorExtension()); |
| 616 TaskRunner backend_runner(std::move(backend_extensions), false, | 811 FrontendChannelImpl frontend_channel(&frontend_runner, |
| 617 &ready_semaphore, | 812 frontend_context_group_id); |
| 618 startup_data.data ? &startup_data : nullptr); | 813 TaskRunner backend_runner( |
| 814 std::move(backend_extensions), false, &ready_semaphore, |
| 815 startup_data.data ? &startup_data : nullptr, &frontend_channel); |
| 619 ready_semaphore.Wait(); | 816 ready_semaphore.Wait(); |
| 620 SendMessageToBackendExtension::set_backend_task_runner(&backend_runner); | |
| 621 UtilsExtension::set_backend_task_runner(&backend_runner); | 817 UtilsExtension::set_backend_task_runner(&backend_runner); |
| 622 | 818 |
| 623 IsolateData::SetupGlobalTasks frontend_extensions; | |
| 624 frontend_extensions.emplace_back(new UtilsExtension()); | |
| 625 frontend_extensions.emplace_back(new SendMessageToBackendExtension()); | |
| 626 TaskRunner frontend_runner(std::move(frontend_extensions), true, | |
| 627 &ready_semaphore, nullptr); | |
| 628 ready_semaphore.Wait(); | |
| 629 | |
| 630 FrontendChannelImpl frontend_channel(&frontend_runner); | |
| 631 InspectorClientImpl inspector_client(&backend_runner, &frontend_channel, | |
| 632 &ready_semaphore); | |
| 633 ready_semaphore.Wait(); | |
| 634 UtilsExtension::set_inspector_client(&inspector_client); | |
| 635 | |
| 636 task_runners.push_back(&frontend_runner); | 819 task_runners.push_back(&frontend_runner); |
| 637 task_runners.push_back(&backend_runner); | 820 task_runners.push_back(&backend_runner); |
| 638 | 821 |
| 639 for (int i = 1; i < argc; ++i) { | 822 for (int i = 1; i < argc; ++i) { |
| 640 // Ignore unknown flags. | 823 // Ignore unknown flags. |
| 641 if (argv[i] == nullptr || argv[i][0] == '-') continue; | 824 if (argv[i] == nullptr || argv[i][0] == '-') continue; |
| 642 | 825 |
| 643 bool exists = false; | 826 bool exists = false; |
| 644 v8::internal::Vector<const char> chars = | 827 v8::internal::Vector<const char> chars = |
| 645 v8::internal::ReadFile(argv[i], &exists, true); | 828 v8::internal::ReadFile(argv[i], &exists, true); |
| 646 if (!exists) { | 829 if (!exists) { |
| 647 fprintf(stderr, "Internal error: script file doesn't exists: %s\n", | 830 fprintf(stderr, "Internal error: script file doesn't exists: %s\n", |
| 648 argv[i]); | 831 argv[i]); |
| 649 Exit(); | 832 Exit(); |
| 650 } | 833 } |
| 651 frontend_runner.Append(new ExecuteStringTask(chars)); | 834 frontend_runner.Append( |
| 835 new ExecuteStringTask(chars, frontend_context_group_id)); |
| 652 } | 836 } |
| 653 | 837 |
| 654 frontend_runner.Join(); | 838 frontend_runner.Join(); |
| 655 backend_runner.Join(); | 839 backend_runner.Join(); |
| 656 | 840 |
| 657 delete startup_data.data; | 841 delete startup_data.data; |
| 658 return 0; | 842 return 0; |
| 659 } | 843 } |
| OLD | NEW |