| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,6 +2,7 @@ | |||
| 2 | 2 | #if HAVE_OPENSSL | |
| 3 | 3 | #include "crypto/crypto_util.h" | |
| 4 | 4 | #endif // HAVE_OPENSSL | |
| 5 | + #include "env.h" | ||
| 5 | 6 | #include "env_properties.h" | |
| 6 | 7 | #include "node.h" | |
| 7 | 8 | #include "node_builtins.h" | |
@@ -1075,6 +1076,18 @@ Maybe<bool> InitializeContext(Local<Context> context) { | |||
| 1075 | 1076 | return Just(true); | |
| 1076 | 1077 | } | |
| 1077 | 1078 | ||
| 1079 | + void RegisterContext(Environment* env, | ||
| 1080 | + v8::Local<v8::Context> context, | ||
| 1081 | + std::string_view name, | ||
| 1082 | + std::string_view origin) { | ||
| 1083 | + ContextInfo info{std::string(name), std::string(origin)}; | ||
| 1084 | + env->AssignToContext(context, nullptr, info); | ||
| 1085 | + } | ||
| 1086 | + | ||
| 1087 | + void UnregisterContext(Environment* env, v8::Local<v8::Context> context) { | ||
| 1088 | + env->UnassignFromContext(context); | ||
| 1089 | + } | ||
| 1090 | + | ||
| 1078 | 1091 | uv_loop_t* GetCurrentEventLoop(Isolate* isolate) { | |
| 1079 | 1092 | HandleScope handle_scope(isolate); | |
| 1080 | 1093 | Local<Context> context = isolate->GetCurrentContext(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -255,6 +255,8 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer { | |||
| 255 | 255 | ||
| 256 | 256 | struct ContextInfo { | |
| 257 | 257 | explicit ContextInfo(const std::string& name) : name(name) {} | |
| 258 | + ContextInfo(const std::string& name, const std::string& origin) | ||
| 259 | + : name(name), origin(origin) {} | ||
| 258 | 260 | const std::string name; | |
| 259 | 261 | std::string origin; | |
| 260 | 262 | bool is_default = false; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -608,6 +608,8 @@ NODE_EXTERN v8::Isolate* NewIsolate( | |||
| 608 | 608 | const IsolateSettings& settings = {}); | |
| 609 | 609 | ||
| 610 | 610 | // Creates a new context with Node.js-specific tweaks. | |
| 611 | + // Call `RegisterContext` after the context been created to register | ||
| 612 | + // the context with Node.js specific setups like the inspector. | ||
| 611 | 613 | NODE_EXTERN v8::Local<v8::Context> NewContext( | |
| 612 | 614 | v8::Isolate* isolate, | |
| 613 | 615 | v8::Local<v8::ObjectTemplate> object_template = | |
@@ -617,6 +619,18 @@ NODE_EXTERN v8::Local<v8::Context> NewContext( | |||
| 617 | 619 | // Return value indicates success of operation | |
| 618 | 620 | NODE_EXTERN v8::Maybe<bool> InitializeContext(v8::Local<v8::Context> context); | |
| 619 | 621 | ||
| 622 | + // Associate the context with the given Environment. This registers the context | ||
| 623 | + // as known to Node.js, makes it available to the inspector. This also registers | ||
| 624 | + // Node.js promise hooks on the context. | ||
| 625 | + NODE_EXTERN void RegisterContext(Environment* env, | ||
| 626 | + v8::Local<v8::Context> context, | ||
| 627 | + std::string_view name = "", | ||
| 628 | + std::string_view origin = ""); | ||
| 629 | + // Unregister the context. Call this when the embedder finished all work with | ||
| 630 | + // this context. | ||
| 631 | + NODE_EXTERN void UnregisterContext(Environment* env, | ||
| 632 | + v8::Local<v8::Context> context); | ||
| 633 | + | ||
| 620 | 634 | // If `platform` is passed, it will be used to register new Worker instances. | |
| 621 | 635 | // It can be `nullptr`, in which case creating new Workers inside of | |
| 622 | 636 | // Environments that use this `IsolateData` will not work. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,69 @@ | |||
| 1 | + #include <node.h> | ||
| 2 | + #include <v8.h> | ||
| 3 | + | ||
| 4 | + namespace { | ||
| 5 | + | ||
| 6 | + using v8::Context; | ||
| 7 | + using v8::FunctionCallbackInfo; | ||
| 8 | + using v8::HandleScope; | ||
| 9 | + using v8::Isolate; | ||
| 10 | + using v8::Local; | ||
| 11 | + using v8::Object; | ||
| 12 | + using v8::Script; | ||
| 13 | + using v8::String; | ||
| 14 | + using v8::Value; | ||
| 15 | + | ||
| 16 | + void MakeContext(const FunctionCallbackInfo<Value>& args) { | ||
| 17 | + Isolate* isolate = Isolate::GetCurrent(); | ||
| 18 | + HandleScope handle_scope(isolate); | ||
| 19 | + Local<Context> context = isolate->GetCurrentContext(); | ||
| 20 | + node::Environment* env = node::GetCurrentEnvironment(context); | ||
| 21 | + assert(env); | ||
| 22 | + | ||
| 23 | + // Create a new context with Node.js-specific setup. | ||
| 24 | + v8::MaybeLocal<Context> maybe_context = node::NewContext(isolate); | ||
| 25 | + v8::Local<Context> new_context; | ||
| 26 | + if (!maybe_context.ToLocal(&new_context)) { | ||
| 27 | + return; | ||
| 28 | + } | ||
| 29 | + node::RegisterContext(env, new_context, "Addon Context", "addon://about"); | ||
| 30 | + | ||
| 31 | + // Return the global proxy object. | ||
| 32 | + args.GetReturnValue().Set(new_context->Global()); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + void RunInContext(const FunctionCallbackInfo<Value>& args) { | ||
| 36 | + Isolate* isolate = Isolate::GetCurrent(); | ||
| 37 | + HandleScope handle_scope(isolate); | ||
| 38 | + assert(args.Length() == 2); | ||
| 39 | + | ||
| 40 | + assert(args[0]->IsObject()); | ||
| 41 | + Local<Object> global_proxy = args[0].As<Object>(); | ||
| 42 | + v8::MaybeLocal<Context> maybe_context = global_proxy->GetCreationContext(); | ||
| 43 | + v8::Local<Context> new_context; | ||
| 44 | + if (!maybe_context.ToLocal(&new_context)) { | ||
| 45 | + return; | ||
| 46 | + } | ||
| 47 | + Context::Scope context_scope(new_context); | ||
| 48 | + | ||
| 49 | + assert(args[1]->IsString()); | ||
| 50 | + Local<String> source = args[1].As<String>(); | ||
| 51 | + Local<Script> script; | ||
| 52 | + Local<Value> result; | ||
| 53 | + | ||
| 54 | + if (Script::Compile(new_context, source).ToLocal(&script) && | ||
| 55 | + script->Run(new_context).ToLocal(&result)) { | ||
| 56 | + args.GetReturnValue().Set(result); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + void Initialize(Local<Object> exports, | ||
| 61 | + Local<Value> module, | ||
| 62 | + Local<Context> context) { | ||
| 63 | + NODE_SET_METHOD(exports, "makeContext", MakeContext); | ||
| 64 | + NODE_SET_METHOD(exports, "runInContext", RunInContext); | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + } // anonymous namespace | ||
| 68 | + | ||
| 69 | + NODE_MODULE_CONTEXT_AWARE(NODE_GYP_MODULE_NAME, Initialize) | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,9 @@ | |||
| 1 | + { | ||
| 2 | + 'targets': [ | ||
| 3 | + { | ||
| 4 | + 'target_name': 'binding', | ||
| 5 | + 'sources': ['binding.cc'], | ||
| 6 | + 'includes': ['../common.gypi'], | ||
| 7 | + }, | ||
| 8 | + ] | ||
| 9 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,51 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../../common'); | ||
| 4 | + common.skipIfInspectorDisabled(); | ||
| 5 | + | ||
| 6 | + const assert = require('node:assert'); | ||
| 7 | + const { once } = require('node:events'); | ||
| 8 | + const { Session } = require('node:inspector'); | ||
| 9 | + | ||
| 10 | + const binding = require(`./build/${common.buildType}/binding`); | ||
| 11 | + | ||
| 12 | + const session = new Session(); | ||
| 13 | + session.connect(); | ||
| 14 | + | ||
| 15 | + (async function() { | ||
| 16 | + const mainContextPromise = | ||
| 17 | + once(session, 'Runtime.executionContextCreated'); | ||
| 18 | + session.post('Runtime.enable', assert.ifError); | ||
| 19 | + await mainContextPromise; | ||
| 20 | + | ||
| 21 | + // Addon-created context should be reported to the inspector. | ||
| 22 | + { | ||
| 23 | + const addonContextPromise = | ||
| 24 | + once(session, 'Runtime.executionContextCreated'); | ||
| 25 | + | ||
| 26 | + const ctx = binding.makeContext(); | ||
| 27 | + const result = binding.runInContext(ctx, '1 + 1'); | ||
| 28 | + assert.strictEqual(result, 2); | ||
| 29 | + | ||
| 30 | + const { 0: contextCreated } = await addonContextPromise; | ||
| 31 | + const { name, origin, auxData } = contextCreated.params.context; | ||
| 32 | + assert.strictEqual(name, 'Addon Context', | ||
| 33 | + JSON.stringify(contextCreated)); | ||
| 34 | + assert.strictEqual(origin, 'addon://about', | ||
| 35 | + JSON.stringify(contextCreated)); | ||
| 36 | + assert.strictEqual(auxData.isDefault, false, | ||
| 37 | + JSON.stringify(contextCreated)); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + // `debugger` statement should pause in addon-created context. | ||
| 41 | + { | ||
| 42 | + session.post('Debugger.enable', assert.ifError); | ||
| 43 | + | ||
| 44 | + const pausedPromise = once(session, 'Debugger.paused'); | ||
| 45 | + const ctx = binding.makeContext(); | ||
| 46 | + binding.runInContext(ctx, 'debugger'); | ||
| 47 | + await pausedPromise; | ||
| 48 | + | ||
| 49 | + session.post('Debugger.resume'); | ||
| 50 | + } | ||
| 51 | + })().then(common.mustCall()); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,18 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + | ||
| 3 | + const common = require('../../common'); | ||
| 4 | + const assert = require('assert'); | ||
| 5 | + | ||
| 6 | + const binding = require(`./build/${common.buildType}/binding`); | ||
| 7 | + | ||
| 8 | + // This verifies that the addon-created context has an independent | ||
| 9 | + // global object. | ||
| 10 | + { | ||
| 11 | + const ctx = binding.makeContext(); | ||
| 12 | + const result = binding.runInContext(ctx, ` | ||
| 13 | + globalThis.foo = 'bar'; | ||
| 14 | + foo; | ||
| 15 | + `); | ||
| 16 | + assert.strictEqual(result, 'bar'); | ||
| 17 | + assert.strictEqual(globalThis.foo, undefined); | ||
| 18 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments