|
4 | 4 | #include <notify.h> |
5 | 5 | #include <chrono> |
6 | 6 | #include "JsV8InspectorClient.h" |
| 7 | +#include "include/libplatform/libplatform.h" |
7 | 8 | #include "src/inspector/v8-inspector-session-impl.h" |
8 | 9 | #include "src/inspector/v8-log-agent-impl.h" |
9 | 10 | #include "Helpers.h" |
@@ -28,6 +29,7 @@ id inspectorLock() { |
28 | 29 | } |
29 | 30 | static int currentInspectorPort = 0; |
30 | 31 | static dispatch_io_t inspector_io = nil; |
| 32 | +static BOOL isWaitingForDebugger = NO; |
31 | 33 | static TNSInspectorSendMessageBlock globalSendMessageToFrontend = nullptr; |
32 | 34 |
|
33 | 35 | #define CheckError(retval, handler) \ |
@@ -212,7 +214,7 @@ static dispatch_source_t createInspectorServer(TNSInspectorFrontendConnectedHand |
212 | 214 | return listenSource; |
213 | 215 | } |
214 | 216 |
|
215 | | -void JsV8InspectorClient::enableInspector() { |
| 217 | +void JsV8InspectorClient::enableInspector(int argc, char** argv) { |
216 | 218 | __block dispatch_source_t listenSource = nil; |
217 | 219 | __block dispatch_io_t current_connection_inspector_io = nil; |
218 | 220 |
|
@@ -252,6 +254,16 @@ static dispatch_source_t createInspectorServer(TNSInspectorFrontendConnectedHand |
252 | 254 | current_connection_inspector_io = io; |
253 | 255 | } |
254 | 256 |
|
| 257 | + if (isWaitingForDebugger) { |
| 258 | + isWaitingForDebugger = NO; |
| 259 | + CFRunLoopRef runloop = CFRunLoopGetMain(); |
| 260 | + CFRunLoopPerformBlock(runloop, (__bridge CFTypeRef)(NSRunLoopCommonModes), ^{ |
| 261 | + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, false); |
| 262 | + this->scheduleBreak(); |
| 263 | + }); |
| 264 | + CFRunLoopWakeUp(runloop); |
| 265 | + } |
| 266 | + |
255 | 267 | return ^(NSString* message, NSError* error) { |
256 | 268 | if (message != nil) { |
257 | 269 | dispatch_sync(this->messagesQueue_, ^{ |
@@ -281,6 +293,27 @@ static dispatch_source_t createInspectorServer(TNSInspectorFrontendConnectedHand |
281 | 293 |
|
282 | 294 | listenSource = createInspectorServer(connectionHandler, ioErrorHandler, clearInspector); |
283 | 295 |
|
| 296 | + int waitForDebuggerSubscription; |
| 297 | + notify_register_dispatch(NOTIFICATION("WaitForDebugger"), &waitForDebuggerSubscription, dispatch_get_main_queue(), ^(int token) { |
| 298 | + isWaitingForDebugger = YES; |
| 299 | + |
| 300 | + dispatch_time_t delay = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 30); |
| 301 | + dispatch_after(delay, dispatch_get_main_queue(), ^{ |
| 302 | + if (isWaitingForDebugger) { |
| 303 | + isWaitingForDebugger = NO; |
| 304 | + NSLog(@"NativeScript waiting for debugger timeout elapsed. Continuing execution."); |
| 305 | + } |
| 306 | + }); |
| 307 | + |
| 308 | + NSLog(@"NativeScript waiting for debugger."); |
| 309 | + CFRunLoopPerformBlock(CFRunLoopGetMain(), kCFRunLoopDefaultMode, ^{ |
| 310 | + do { |
| 311 | + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1, false); |
| 312 | + } while (isWaitingForDebugger); |
| 313 | + }); |
| 314 | + CFRunLoopWakeUp(CFRunLoopGetMain()); |
| 315 | + }); |
| 316 | + |
284 | 317 | int attachRequestSubscription; |
285 | 318 | notify_register_dispatch(NOTIFICATION("AttachRequest"), &attachRequestSubscription, dispatch_get_main_queue(), ^(int token) { |
286 | 319 | clear(); |
@@ -290,12 +323,34 @@ static dispatch_source_t createInspectorServer(TNSInspectorFrontendConnectedHand |
290 | 323 | notify_post(NOTIFICATION("ReadyForAttach")); |
291 | 324 | }); |
292 | 325 |
|
| 326 | + notify_post(NOTIFICATION("AppLaunching")); |
| 327 | + |
| 328 | + for (int i = 1; i < argc; i++) { |
| 329 | + BOOL startListening = NO; |
| 330 | + BOOL shouldWaitForDebugger = NO; |
| 331 | + |
| 332 | + if (strcmp(argv[i], "--nativescript-debug-brk") == 0) { |
| 333 | + shouldWaitForDebugger = YES; |
| 334 | + } else if (strcmp(argv[i], "--nativescript-debug-start") == 0) { |
| 335 | + startListening = YES; |
| 336 | + } |
| 337 | + |
| 338 | + if (startListening || shouldWaitForDebugger) { |
| 339 | + notify_post(NOTIFICATION("AttachRequest")); |
| 340 | + if (shouldWaitForDebugger) { |
| 341 | + notify_post(NOTIFICATION("WaitForDebugger")); |
| 342 | + } |
| 343 | + |
| 344 | + break; |
| 345 | + } |
| 346 | + } |
| 347 | + |
293 | 348 | CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.5, false); |
| 349 | + notify_cancel(waitForDebuggerSubscription); |
294 | 350 | } |
295 | 351 |
|
296 | | -JsV8InspectorClient::JsV8InspectorClient(v8::Platform* platform, Isolate* isolate) |
297 | | - : platform_(platform), |
298 | | - isolate_(isolate), |
| 352 | +JsV8InspectorClient::JsV8InspectorClient(tns::Runtime* runtime) |
| 353 | + : runtime_(runtime), |
299 | 354 | messages_(), |
300 | 355 | runningNestedLoops_(false) { |
301 | 356 | this->messagesQueue_ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); |
@@ -306,31 +361,33 @@ static dispatch_source_t createInspectorServer(TNSInspectorFrontendConnectedHand |
306 | 361 | return; |
307 | 362 | } |
308 | 363 |
|
309 | | - v8::HandleScope handle_scope(isolate_); |
| 364 | + Isolate* isolate = runtime_->GetIsolate(); |
| 365 | + HandleScope handle_scope(isolate); |
310 | 366 |
|
311 | | - v8::Local<Context> context = isolate_->GetCurrentContext(); |
| 367 | + Local<Context> context = isolate->GetCurrentContext(); |
312 | 368 |
|
313 | | - inspector_ = V8Inspector::create(isolate_, this); |
| 369 | + inspector_ = V8Inspector::create(isolate, this); |
314 | 370 |
|
315 | 371 | inspector_->contextCreated(v8_inspector::V8ContextInfo(context, JsV8InspectorClient::contextGroupId, v8_inspector::StringView())); |
316 | 372 |
|
317 | | - v8::Persistent<v8::Context> persistentContext(context->GetIsolate(), JsV8InspectorClient::PersistentToLocal(isolate_, context_)); |
318 | | - context_.Reset(isolate_, persistentContext); |
| 373 | + Persistent<Context> persistentContext(context->GetIsolate(), JsV8InspectorClient::PersistentToLocal(isolate, context_)); |
| 374 | + context_.Reset(isolate, persistentContext); |
319 | 375 |
|
320 | 376 | this->createInspectorSession(); |
321 | 377 | } |
322 | 378 |
|
323 | | -void JsV8InspectorClient::connect() { |
| 379 | +void JsV8InspectorClient::connect(int argc, char** argv) { |
324 | 380 | this->isConnected_ = true; |
325 | | - this->enableInspector(); |
| 381 | + this->enableInspector(argc, argv); |
326 | 382 | } |
327 | 383 |
|
328 | 384 | void JsV8InspectorClient::createInspectorSession() { |
329 | 385 | this->session_ = this->inspector_->connect(JsV8InspectorClient::contextGroupId, this, v8_inspector::StringView()); |
330 | 386 | } |
331 | 387 |
|
332 | 388 | void JsV8InspectorClient::disconnect() { |
333 | | - v8::HandleScope handleScope(isolate_); |
| 389 | + Isolate* isolate = runtime_->GetIsolate(); |
| 390 | + HandleScope handleScope(isolate); |
334 | 391 |
|
335 | 392 | session_->resume(); |
336 | 393 | session_.reset(); |
@@ -353,7 +410,9 @@ static dispatch_source_t createInspectorServer(TNSInspectorFrontendConnectedHand |
353 | 410 | this->dispatchMessage(message); |
354 | 411 | } |
355 | 412 |
|
356 | | - while (v8::platform::PumpMessageLoop(platform_, isolate_)) { |
| 413 | + Platform* platform = tns::Runtime::GetPlatform(); |
| 414 | + Isolate* isolate = runtime_->GetIsolate(); |
| 415 | + while (platform::PumpMessageLoop(platform, isolate)) { |
357 | 416 | } |
358 | 417 | } |
359 | 418 |
|
@@ -393,7 +452,8 @@ static dispatch_source_t createInspectorServer(TNSInspectorFrontendConnectedHand |
393 | 452 | } |
394 | 453 |
|
395 | 454 | Local<Context> JsV8InspectorClient::ensureDefaultContextInGroup(int contextGroupId) { |
396 | | - v8::Local<v8::Context> context = PersistentToLocal(isolate_, context_); |
| 455 | + Isolate* isolate = runtime_->GetIsolate(); |
| 456 | + Local<Context> context = PersistentToLocal(isolate, context_); |
397 | 457 | return context; |
398 | 458 | } |
399 | 459 |
|
@@ -410,43 +470,50 @@ static dispatch_source_t createInspectorServer(TNSInspectorFrontendConnectedHand |
410 | 470 | } |
411 | 471 |
|
412 | 472 | template<class TypeName> |
413 | | -inline v8::Local<TypeName> StrongPersistentToLocal(const v8::Persistent<TypeName>& persistent) { |
414 | | - return *reinterpret_cast<v8::Local<TypeName> *>(const_cast<v8::Persistent<TypeName> *>(&persistent)); |
| 473 | +inline Local<TypeName> StrongPersistentToLocal(const Persistent<TypeName>& persistent) { |
| 474 | + return *reinterpret_cast<Local<TypeName> *>(const_cast<Persistent<TypeName> *>(&persistent)); |
415 | 475 | } |
416 | 476 |
|
417 | 477 | template<class TypeName> |
418 | | -inline v8::Local<TypeName> WeakPersistentToLocal(v8::Isolate* isolate, const v8::Persistent<TypeName>& persistent) { |
419 | | - return v8::Local<TypeName>::New(isolate, persistent); |
| 478 | +inline Local<TypeName> WeakPersistentToLocal(Isolate* isolate, const Persistent<TypeName>& persistent) { |
| 479 | + return Local<TypeName>::New(isolate, persistent); |
420 | 480 | } |
421 | 481 |
|
422 | 482 | template<class TypeName> |
423 | | -inline v8::Local<TypeName> JsV8InspectorClient::PersistentToLocal(v8::Isolate* isolate, const v8::Persistent<TypeName>& persistent) { |
| 483 | +inline Local<TypeName> JsV8InspectorClient::PersistentToLocal(Isolate* isolate, const Persistent<TypeName>& persistent) { |
424 | 484 | if (persistent.IsWeak()) { |
425 | 485 | return WeakPersistentToLocal(isolate, persistent); |
426 | 486 | } else { |
427 | 487 | return StrongPersistentToLocal(persistent); |
428 | 488 | } |
429 | 489 | } |
430 | 490 |
|
431 | | -void JsV8InspectorClient::registerModules(std::function<void(v8::Isolate*, std::string)> runModule) { |
432 | | - HandleScope scope(isolate_); |
433 | | - Local<Context> context = isolate_->GetCurrentContext(); |
| 491 | +void JsV8InspectorClient::scheduleBreak() { |
| 492 | + Isolate* isolate = runtime_->GetIsolate(); |
| 493 | + HandleScope scope(isolate); |
| 494 | + this->session_->schedulePauseOnNextStatement(StringView(), StringView()); |
| 495 | +} |
| 496 | + |
| 497 | +void JsV8InspectorClient::registerModules() { |
| 498 | + Isolate* isolate = runtime_->GetIsolate(); |
| 499 | + HandleScope scope(isolate); |
| 500 | + Local<Context> context = isolate->GetCurrentContext(); |
434 | 501 | Local<Object> global = context->Global(); |
435 | | - Local<Object> inspectorObject = Object::New(isolate_); |
| 502 | + Local<Object> inspectorObject = Object::New(isolate); |
436 | 503 |
|
437 | | - assert(global->Set(context, tns::ToV8String(isolate_, "__inspector"), inspectorObject).FromMaybe(false)); |
438 | | - v8::Local<v8::Function> func; |
| 504 | + assert(global->Set(context, tns::ToV8String(isolate, "__inspector"), inspectorObject).FromMaybe(false)); |
| 505 | + Local<v8::Function> func; |
439 | 506 | bool success = v8::Function::New(context, registerDomainDispatcherCallback).ToLocal(&func); |
440 | | - assert(success && global->Set(context, tns::ToV8String(isolate_, "__registerDomainDispatcher"), func).FromMaybe(false)); |
| 507 | + assert(success && global->Set(context, tns::ToV8String(isolate, "__registerDomainDispatcher"), func).FromMaybe(false)); |
441 | 508 |
|
442 | | - Local<External> data = External::New(isolate_, this); |
| 509 | + Local<External> data = External::New(isolate, this); |
443 | 510 | success = v8::Function::New(context, inspectorSendEventCallback, data).ToLocal(&func); |
444 | | - assert(success && global->Set(context, tns::ToV8String(isolate_, "__inspectorSendEvent"), func).FromMaybe(false)); |
| 511 | + assert(success && global->Set(context, tns::ToV8String(isolate, "__inspectorSendEvent"), func).FromMaybe(false)); |
445 | 512 |
|
446 | 513 | success = v8::Function::New(context, inspectorTimestampCallback).ToLocal(&func); |
447 | | - assert(success && global->Set(context, tns::ToV8String(isolate_, "__inspectorTimestamp"), func).FromMaybe(false)); |
| 514 | + assert(success && global->Set(context, tns::ToV8String(isolate, "__inspectorTimestamp"), func).FromMaybe(false)); |
448 | 515 |
|
449 | | - runModule(isolate_, "inspector_modules"); |
| 516 | + runtime_->RunModule("inspector_modules"); |
450 | 517 | } |
451 | 518 |
|
452 | 519 | void JsV8InspectorClient::registerDomainDispatcherCallback(const FunctionCallbackInfo<Value>& args) { |
@@ -484,15 +551,15 @@ static dispatch_source_t createInspectorServer(TNSInspectorFrontendConnectedHand |
484 | 551 | client->dispatchMessage(message); |
485 | 552 | } |
486 | 553 |
|
487 | | -void JsV8InspectorClient::inspectorTimestampCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 554 | +void JsV8InspectorClient::inspectorTimestampCallback(const FunctionCallbackInfo<Value>& args) { |
488 | 555 | Isolate* isolate = args.GetIsolate(); |
489 | 556 | double timestamp = std::chrono::seconds(std::chrono::seconds(std::time(NULL))).count(); |
490 | 557 | Local<Number> result = Number::New(isolate, timestamp); |
491 | 558 | args.GetReturnValue().Set(result); |
492 | 559 | } |
493 | 560 |
|
494 | 561 | int JsV8InspectorClient::contextGroupId = 1; |
495 | | -std::map<std::string, v8::Persistent<v8::Object>*> JsV8InspectorClient::Domains; |
| 562 | +std::map<std::string, Persistent<Object>*> JsV8InspectorClient::Domains; |
496 | 563 |
|
497 | 564 | } |
498 | 565 |
|