Skip to content

Commit

Permalink
src: add an ExternalReferenceRegistry class
Browse files Browse the repository at this point in the history
Add an ExternalReferenceRegistry class for registering static
external references.

To register the external JS to C++ references created in a binding
(e.g. when a FunctionTemplate is created):

- Add the binding name (same as the id used for `internalBinding()`
  and `NODE_MODULE_CONTEXT_AWARE_INTERNAL`) to
  `EXTERNAL_REFERENCE_BINDING_LIST` in `src/node_external_reference.h`.
- In the file where the binding is implemented, create a registration
  function to register the static C++ references (e.g. the C++
  functions in `v8::FunctionCallback` associated with the function
  templates), like this:

  ```c++
  void RegisterExternalReferences(
          ExternalReferenceRegistry* registry) {
    registry->Register(cpp_func_1);
  }
  ```
- At the end of the file where `NODE_MODULE_CONTEXT_AWARE_INTERNAL` is
  also usually called, register the registration function with

  ```
  NODE_MODULE_EXTERNAL_REFERENCE(binding_name,
                                 RegisterExternalReferences);
  ```

PR-URL: #32984
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Daniel Bevenius <[email protected]>
  • Loading branch information
joyeecheung committed Jul 18, 2020
1 parent 404302f commit ef9964f
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 5 deletions.
2 changes: 2 additions & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,7 @@
'src/node_dir.cc',
'src/node_env_var.cc',
'src/node_errors.cc',
'src/node_external_reference.cc',
'src/node_file.cc',
'src/node_http_parser.cc',
'src/node_http2.cc',
Expand Down Expand Up @@ -687,6 +688,7 @@
'src/node_contextify.h',
'src/node_dir.h',
'src/node_errors.h',
'src/node_external_reference.h',
'src/node_file.h',
'src/node_file-inl.h',
'src/node_http_common.h',
Expand Down
1 change: 1 addition & 0 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,7 @@ int Start(int argc, char** argv) {
if (blob != nullptr) {
// TODO(joyeecheung): collect external references and set it in
// params.external_references.
external_references = NodeMainInstance::CollectExternalReferences();
external_references.push_back(reinterpret_cast<intptr_t>(nullptr));
params.external_references = external_references.data();
params.snapshot_blob = blob;
Expand Down
22 changes: 22 additions & 0 deletions src/node_external_reference.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#include "node_external_reference.h"
#include <cinttypes>
#include <vector>
#include "util.h"

namespace node {

const std::vector<intptr_t>& ExternalReferenceRegistry::external_references() {
CHECK(!is_finalized_);
external_references_.push_back(reinterpret_cast<intptr_t>(nullptr));
is_finalized_ = true;
return external_references_;
}

ExternalReferenceRegistry::ExternalReferenceRegistry() {
#define V(modname) _register_external_reference_##modname(this);
EXTERNAL_REFERENCE_BINDING_LIST(V)
#undef V
// TODO(joyeecheung): collect more external references here.
}

} // namespace node
67 changes: 67 additions & 0 deletions src/node_external_reference.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#ifndef SRC_NODE_EXTERNAL_REFERENCE_H_
#define SRC_NODE_EXTERNAL_REFERENCE_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include <cinttypes>
#include <vector>
#include "v8.h"

namespace node {

// This class manages the external references from the V8 heap
// to the C++ addresses in Node.js.
class ExternalReferenceRegistry {
public:
ExternalReferenceRegistry();

#define ALLOWED_EXTERNAL_REFERENCE_TYPES(V) \
V(v8::FunctionCallback) \
V(v8::AccessorGetterCallback) \
V(v8::AccessorSetterCallback) \
V(v8::AccessorNameGetterCallback) \
V(v8::AccessorNameSetterCallback) \
V(v8::GenericNamedPropertyDefinerCallback) \
V(v8::GenericNamedPropertyDeleterCallback) \
V(v8::GenericNamedPropertyEnumeratorCallback) \
V(v8::GenericNamedPropertyQueryCallback) \
V(v8::GenericNamedPropertySetterCallback)

#define V(ExternalReferenceType) \
void Register(ExternalReferenceType addr) { RegisterT(addr); }
ALLOWED_EXTERNAL_REFERENCE_TYPES(V)
#undef V

// This can be called only once.
const std::vector<intptr_t>& external_references();

bool is_empty() { return external_references_.empty(); }

private:
template <typename T>
void RegisterT(T* address) {
external_references_.push_back(reinterpret_cast<intptr_t>(address));
}
bool is_finalized_ = false;
std::vector<intptr_t> external_references_;
};

#define EXTERNAL_REFERENCE_BINDING_LIST(V)

} // namespace node

// Declare all the external reference registration functions here,
// and define them later with #NODE_MODULE_EXTERNAL_REFERENCE(modname, func);
#define V(modname) \
void _register_external_reference_##modname( \
node::ExternalReferenceRegistry* registry);
EXTERNAL_REFERENCE_BINDING_LIST(V)
#undef V

#define NODE_MODULE_EXTERNAL_REFERENCE(modname, func) \
void _register_external_reference_##modname( \
node::ExternalReferenceRegistry* registry) { \
func(registry); \
}
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
#endif // SRC_NODE_EXTERNAL_REFERENCE_H_
15 changes: 14 additions & 1 deletion src/node_main_instance.cc
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
#include <memory>

#include "node_main_instance.h"
#include "node_errors.h"
#include "node_external_reference.h"
#include "node_internals.h"
#include "node_main_instance.h"
#include "node_options-inl.h"
#include "node_v8_platform-inl.h"
#include "util-inl.h"
Expand All @@ -22,6 +24,8 @@ using v8::Local;
using v8::Locker;
using v8::SealHandleScope;

std::unique_ptr<ExternalReferenceRegistry> NodeMainInstance::registry_ =
nullptr;
NodeMainInstance::NodeMainInstance(Isolate* isolate,
uv_loop_t* event_loop,
MultiIsolatePlatform* platform,
Expand All @@ -41,6 +45,15 @@ NodeMainInstance::NodeMainInstance(Isolate* isolate,
SetIsolateMiscHandlers(isolate_, {});
}

const std::vector<intptr_t>& NodeMainInstance::CollectExternalReferences() {
// Cannot be called more than once.
CHECK_NULL(registry_);
registry_.reset(new ExternalReferenceRegistry());

// TODO(joyeecheung): collect more external references here.
return registry_->external_references();
}

std::unique_ptr<NodeMainInstance> NodeMainInstance::Create(
Isolate* isolate,
uv_loop_t* event_loop,
Expand Down
4 changes: 4 additions & 0 deletions src/node_main_instance.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

namespace node {

class ExternalReferenceRegistry;

// TODO(joyeecheung): align this with the Worker/WorkerThreadData class.
// We may be able to create an abstract class to reuse some of the routines.
class NodeMainInstance {
Expand Down Expand Up @@ -66,6 +68,7 @@ class NodeMainInstance {
// snapshot.
static const std::vector<size_t>* GetIsolateDataIndexes();
static v8::StartupData* GetEmbeddedSnapshotBlob();
static const std::vector<intptr_t>& CollectExternalReferences();

static const size_t kNodeContextIndex = 0;
NodeMainInstance(const NodeMainInstance&) = delete;
Expand All @@ -80,6 +83,7 @@ class NodeMainInstance {
const std::vector<std::string>& args,
const std::vector<std::string>& exec_args);

static std::unique_ptr<ExternalReferenceRegistry> registry_;
std::vector<std::string> args_;
std::vector<std::string> exec_args_;
std::unique_ptr<ArrayBufferAllocator> array_buffer_allocator_;
Expand Down
8 changes: 4 additions & 4 deletions tools/snapshot/snapshot_builder.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "snapshot_builder.h"
#include <iostream>
#include <sstream>
#include "env-inl.h"
#include "node_external_reference.h"
#include "node_internals.h"
#include "node_main_instance.h"
#include "node_v8_platform-inl.h"
Expand Down Expand Up @@ -63,10 +65,8 @@ const std::vector<size_t>* NodeMainInstance::GetIsolateDataIndexes() {
std::string SnapshotBuilder::Generate(
const std::vector<std::string> args,
const std::vector<std::string> exec_args) {
// TODO(joyeecheung): collect external references and set it in
// params.external_references.
std::vector<intptr_t> external_references = {
reinterpret_cast<intptr_t>(nullptr)};
const std::vector<intptr_t>& external_references =
NodeMainInstance::CollectExternalReferences();
Isolate* isolate = Isolate::Allocate();
per_process::v8_platform.Platform()->RegisterIsolate(isolate,
uv_default_loop());
Expand Down

0 comments on commit ef9964f

Please sign in to comment.