Skip to content

Commit

Permalink
lib: support returning Safe collections from C++
Browse files Browse the repository at this point in the history
Co-authored-by: Antoine du Hamel <duhamelantoine1995@gmail.com>

PR-URL: #36989
Refs: #36652
Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
ExE-Boss authored and targos committed May 30, 2021
1 parent bd298f7 commit 26bd60e
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,29 @@ void Environment::CreateProperties() {
CHECK(primordials->IsObject());
set_primordials(primordials.As<Object>());

Local<String> prototype_string =
FIXED_ONE_BYTE_STRING(isolate(), "prototype");

#define V(EnvPropertyName, PrimordialsPropertyName) \
{ \
Local<Value> ctor = \
primordials.As<Object>() \
->Get(ctx, \
FIXED_ONE_BYTE_STRING(isolate(), PrimordialsPropertyName)) \
.ToLocalChecked(); \
CHECK(ctor->IsObject()); \
Local<Value> prototype = \
ctor.As<Object>()->Get(ctx, prototype_string).ToLocalChecked(); \
CHECK(prototype->IsObject()); \
set_##EnvPropertyName(prototype.As<Object>()); \
}

V(primordials_safe_map_prototype_object, "SafeMap");
V(primordials_safe_set_prototype_object, "SafeSet");
V(primordials_safe_weak_map_prototype_object, "SafeWeakMap");
V(primordials_safe_weak_set_prototype_object, "SafeWeakSet");
#undef V

Local<Object> process_object =
node::CreateProcessObject(this).FromMaybe(Local<Object>());
set_process_object(process_object);
Expand Down
4 changes: 4 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,10 @@ constexpr size_t kFsStatsBufferLength =
V(prepare_stack_trace_callback, v8::Function) \
V(process_object, v8::Object) \
V(primordials, v8::Object) \
V(primordials_safe_map_prototype_object, v8::Object) \
V(primordials_safe_set_prototype_object, v8::Object) \
V(primordials_safe_weak_map_prototype_object, v8::Object) \
V(primordials_safe_weak_set_prototype_object, v8::Object) \
V(promise_hook_handler, v8::Function) \
V(promise_reject_callback, v8::Function) \
V(script_data_constructor_function, v8::Function) \
Expand Down
12 changes: 12 additions & 0 deletions src/node_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,12 @@ void GetOptions(const FunctionCallbackInfo<Value>& args) {
});

Local<Map> options = Map::New(isolate);
if (options
->SetPrototype(context, env->primordials_safe_map_prototype_object())
.IsNothing()) {
return;
}

for (const auto& item : _ppop_instance.options_) {
Local<Value> value;
const auto& option_info = item.second;
Expand Down Expand Up @@ -970,6 +976,12 @@ void GetOptions(const FunctionCallbackInfo<Value>& args) {
Local<Value> aliases;
if (!ToV8Value(context, _ppop_instance.aliases_).ToLocal(&aliases)) return;

if (aliases.As<Object>()
->SetPrototype(context, env->primordials_safe_map_prototype_object())
.IsNothing()) {
return;
}

Local<Object> ret = Object::New(isolate);
if (ret->Set(context, env->options_string(), options).IsNothing() ||
ret->Set(context, env->aliases_string(), aliases).IsNothing()) {
Expand Down
2 changes: 2 additions & 0 deletions src/uv.cc
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ void GetErrMap(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = env->isolate();
Local<Context> context = env->context();

// This can't return a SafeMap, because the uv binding can be referenced
// by user code by using `process.binding('uv').getErrorMap()`:
Local<Map> err_map = Map::New(isolate);

size_t errors_len = arraysize(per_process::uv_errors_map);
Expand Down
18 changes: 18 additions & 0 deletions test/parallel/test-options-binding.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Flags: --expose-internals
'use strict';

const common = require('../common');
const { primordials: { SafeMap } } = require('internal/test/binding');

const { options, aliases, getOptionValue } = require('internal/options');
const assert = require('assert');

assert(options instanceof SafeMap,
"require('internal/options').options is a SafeMap");

assert(aliases instanceof SafeMap,
"require('internal/options').aliases is a SafeMap");

Map.prototype.get =
common.mustNotCall('`getOptionValue` must not call user-mutable method');
assert.strictEqual(getOptionValue('--expose-internals'), true);

0 comments on commit 26bd60e

Please sign in to comment.