44#include " env.h"
55#include " env-inl.h"
66#include " node.h"
7+ #include " node_contextify.h"
78#include " v8-inspector.h"
89#include " v8-platform.h"
910#include " util.h"
1011#include " zlib.h"
1112
1213#include " libplatform/libplatform.h"
1314
15+ #include < algorithm>
1416#include < string.h>
1517#include < vector>
1618
2123namespace node {
2224namespace inspector {
2325namespace {
26+
27+ using node::contextify::ContextifyContext;
28+
2429using v8::Context;
2530using v8::External;
2631using v8::Function;
@@ -43,6 +48,10 @@ using v8_inspector::V8Inspector;
4348static uv_sem_t start_io_thread_semaphore;
4449static uv_async_t start_io_thread_async;
4550
51+ // Used in NodeInspectorClient::currentTimeMS() below.
52+ const int NANOS_PER_MSEC = 1000000 ;
53+ const int CONTEXT_GROUP_ID = 1 ;
54+
4655class StartIoTask : public v8 ::Task {
4756 public:
4857 explicit StartIoTask (Agent* agent) : agent(agent) {}
@@ -376,9 +385,61 @@ void CallAndPauseOnStart(
376385 }
377386}
378387
379- // Used in NodeInspectorClient::currentTimeMS() below.
380- const int NANOS_PER_MSEC = 1000000 ;
381- const int CONTEXT_GROUP_ID = 1 ;
388+ void AttachContext (const v8::FunctionCallbackInfo<v8::Value>& args) {
389+ Environment* env = Environment::GetCurrent (args);
390+ if (!args[0 ]->IsObject ()) {
391+ env->ThrowTypeError (" sandbox must be an object" );
392+ return ;
393+ }
394+ Local<Object> sandbox = args[0 ].As <Object>();
395+ ContextifyContext* contextify_context =
396+ ContextifyContext::ContextFromContextifiedSandbox (env, sandbox);
397+ if (contextify_context == nullptr ) {
398+ return env->ThrowTypeError (
399+ " sandbox argument must have been converted to a context." );
400+ }
401+
402+ if (contextify_context->context ().IsEmpty ())
403+ return ;
404+
405+ const char * name =
406+ args[1 ]->IsString () ?
407+ Utf8Value (env->isolate (), args[1 ]).out () :
408+ " vm Module Context" ;
409+ const char * origin =
410+ args[2 ]->IsString () ?
411+ Utf8Value (env->isolate (), args[2 ]).out () :
412+ nullptr ;
413+
414+ // TODO(TimothyGu): Don't allow customizing group ID for now; not sure what
415+ // it's used for.
416+ int group_id = CONTEXT_GROUP_ID;
417+
418+ auto info = new node::inspector::ContextInfo (
419+ contextify_context->context (), group_id, name, origin,
420+ " {\" isDefault\" :false}" );
421+ env->inspector_agent ()->ContextCreated (info);
422+ }
423+
424+ void DetachContext (const v8::FunctionCallbackInfo<v8::Value>& args) {
425+ Environment* env = Environment::GetCurrent (args);
426+ if (!args[0 ]->IsObject ()) {
427+ env->ThrowTypeError (" sandbox must be an object" );
428+ return ;
429+ }
430+ Local<Object> sandbox = args[0 ].As <Object>();
431+ ContextifyContext* contextify_context =
432+ ContextifyContext::ContextFromContextifiedSandbox (env, sandbox);
433+ if (contextify_context == nullptr ) {
434+ return env->ThrowTypeError (
435+ " sandbox argument must have been converted to a context." );
436+ }
437+
438+ if (contextify_context->context ().IsEmpty ())
439+ return ;
440+
441+ env->inspector_agent ()->ContextDestroyed (contextify_context->context ());
442+ }
382443
383444class ChannelImpl final : public v8_inspector::V8Inspector::Channel {
384445 public:
@@ -459,11 +520,24 @@ class NodeInspectorClient : public v8_inspector::V8InspectorClient {
459520 return uv_hrtime () * 1.0 / NANOS_PER_MSEC;
460521 }
461522
462- void contextCreated (Local<Context> context, const std::string& name) {
463- std::unique_ptr<StringBuffer> name_buffer = Utf8ToStringView (name);
464- v8_inspector::V8ContextInfo info (context, CONTEXT_GROUP_ID,
465- name_buffer->string ());
466- client_->contextCreated (info);
523+ void contextCreated (const node::inspector::ContextInfo* info) {
524+ std::unique_ptr<StringBuffer> name_buffer = Utf8ToStringView (info->name ());
525+ v8_inspector::V8ContextInfo v8_info (info->context (env_->isolate ()),
526+ info->group_id (),
527+ name_buffer->string ());
528+
529+ std::unique_ptr<StringBuffer> origin_buffer;
530+ std::unique_ptr<StringBuffer> aux_data_buffer;
531+ if (info->origin () != nullptr ) {
532+ origin_buffer = Utf8ToStringView (info->origin ());
533+ v8_info.origin = origin_buffer->string ();
534+ }
535+ if (info->aux_data () != nullptr ) {
536+ aux_data_buffer = Utf8ToStringView (info->aux_data ());
537+ v8_info.auxData = aux_data_buffer->string ();
538+ }
539+
540+ client_->contextCreated (v8_info);
467541 }
468542
469543 void contextDestroyed (Local<Context> context) {
@@ -546,14 +620,36 @@ Agent::Agent(Environment* env) : parent_env_(env),
546620Agent::~Agent () {
547621}
548622
623+ void Agent::ContextCreated (const node::inspector::ContextInfo* info) {
624+ contexts_.push_back (info);
625+ client_->contextCreated (info);
626+ }
627+
628+ void Agent::ContextDestroyed (Local<Context> context) {
629+ auto it = std::find_if (
630+ contexts_.begin (), contexts_.end (),
631+ [&] (const node::inspector::ContextInfo*& info) {
632+ return info->context (parent_env_->isolate ()) == context;
633+ });
634+ if (it == contexts_.end ()) {
635+ return ;
636+ }
637+ delete *it;
638+ contexts_.erase (it);
639+ client_->contextDestroyed (context);
640+ }
641+
549642bool Agent::Start (v8::Platform* platform, const char * path,
550643 const DebugOptions& options) {
551644 path_ = path == nullptr ? " " : path;
552645 debug_options_ = options;
553646 client_ =
554647 std::unique_ptr<NodeInspectorClient>(
555648 new NodeInspectorClient (parent_env_, platform));
556- client_->contextCreated (parent_env_->context (), " Node.js Main Context" );
649+ ContextCreated (
650+ new node::inspector::ContextInfo (
651+ parent_env_->context (), CONTEXT_GROUP_ID, " Node.js Main Context" ,
652+ nullptr , " {\" isDefault\" :true}" ));
557653 platform_ = platform;
558654 CHECK_EQ (0 , uv_async_init (uv_default_loop (),
559655 &start_io_thread_async,
@@ -627,7 +723,9 @@ bool Agent::IsConnected() {
627723
628724void Agent::WaitForDisconnect () {
629725 CHECK_NE (client_, nullptr );
630- client_->contextDestroyed (parent_env_->context ());
726+ for (const node::inspector::ContextInfo*& info : contexts_) {
727+ ContextDestroyed (info->context (parent_env_->isolate ()));
728+ }
631729 if (io_ != nullptr ) {
632730 io_->WaitForDisconnect ();
633731 }
@@ -713,6 +811,8 @@ void Agent::InitInspector(Local<Object> target, Local<Value> unused,
713811 Environment* env = Environment::GetCurrent (context);
714812 Agent* agent = env->inspector_agent ();
715813 env->SetMethod (target, " consoleCall" , InspectorConsoleCall);
814+ env->SetMethod (target, " attachContext" , AttachContext);
815+ env->SetMethod (target, " detachContext" , DetachContext);
716816 if (agent->debug_options_ .wait_for_connect ())
717817 env->SetMethod (target, " callAndPauseOnStart" , CallAndPauseOnStart);
718818 env->SetMethod (target, " connect" , ConnectJSBindingsSession);
0 commit comments