From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samuel Attard <samuel.r.attard@gmail.com>
Date: Tue, 3 Nov 2020 16:17:38 -0800
Subject: src: allow embedders to provide a custom PageAllocator to
 NodePlatform

For certain embedder use cases there are more complex memory allocation requirements that
the default V8 page allocator does not handle, for example using MAP_JIT when running under
a hardened runtime environment on macOS.  This allows such embedders to provide their own
allocator that does handle these cases.

Upstreamed in https://github.com/nodejs/node/pull/38362.

diff --git a/src/api/environment.cc b/src/api/environment.cc
index 09c0d22ff91856704f61024646c946a39baf53d8..b060a8e980432637c430bd66a5216095984e4381 100644
--- a/src/api/environment.cc
+++ b/src/api/environment.cc
@@ -472,8 +472,9 @@ MultiIsolatePlatform* CreatePlatform(
 
 MultiIsolatePlatform* CreatePlatform(
     int thread_pool_size,
-    v8::TracingController* tracing_controller) {
-  return MultiIsolatePlatform::Create(thread_pool_size, tracing_controller)
+    v8::TracingController* tracing_controller,
+    v8::PageAllocator* page_allocator) {
+  return MultiIsolatePlatform::Create(thread_pool_size, tracing_controller, page_allocator)
       .release();
 }
 
@@ -483,8 +484,9 @@ void FreePlatform(MultiIsolatePlatform* platform) {
 
 std::unique_ptr<MultiIsolatePlatform> MultiIsolatePlatform::Create(
     int thread_pool_size,
-    v8::TracingController* tracing_controller) {
-  return std::make_unique<NodePlatform>(thread_pool_size, tracing_controller);
+    v8::TracingController* tracing_controller,
+    v8::PageAllocator* page_allocator) {
+  return std::make_unique<NodePlatform>(thread_pool_size, tracing_controller, page_allocator);
 }
 
 MaybeLocal<Object> GetPerContextExports(Local<Context> context) {
diff --git a/src/node.h b/src/node.h
index 691c16ba60b0ce8633555825e44c3ace96c5000f..ccb452bbe941c30fdc8c4eb616eb6f0259aa8b8e 100644
--- a/src/node.h
+++ b/src/node.h
@@ -313,7 +313,8 @@ class NODE_EXTERN MultiIsolatePlatform : public v8::Platform {
 
   static std::unique_ptr<MultiIsolatePlatform> Create(
       int thread_pool_size,
-      v8::TracingController* tracing_controller = nullptr);
+      v8::TracingController* tracing_controller = nullptr,
+      v8::PageAllocator* page_allocator = nullptr);
 };
 
 enum IsolateSettingsFlags {
@@ -494,7 +495,8 @@ NODE_EXTERN node::tracing::Agent* CreateAgent();
 NODE_DEPRECATED("Use MultiIsolatePlatform::Create() instead",
     NODE_EXTERN MultiIsolatePlatform* CreatePlatform(
         int thread_pool_size,
-        v8::TracingController* tracing_controller));
+        v8::TracingController* tracing_controller,
+        v8::PageAllocator* = nullptr));
 NODE_DEPRECATED("Use MultiIsolatePlatform::Create() instead",
     NODE_EXTERN void FreePlatform(MultiIsolatePlatform* platform));
 
diff --git a/src/node_platform.cc b/src/node_platform.cc
index eb918bdd559c404a0e311e0dd92cfee8940491bc..5be79694fef65c9290f1b46d2657581dea16f543 100644
--- a/src/node_platform.cc
+++ b/src/node_platform.cc
@@ -324,12 +324,16 @@ void PerIsolatePlatformData::DecreaseHandleCount() {
 }
 
 NodePlatform::NodePlatform(int thread_pool_size,
-                           v8::TracingController* tracing_controller) {
+                           v8::TracingController* tracing_controller,
+                           v8::PageAllocator* page_allocator) {
   if (tracing_controller != nullptr) {
     tracing_controller_ = tracing_controller;
   } else {
     tracing_controller_ = new v8::TracingController();
   }
+  // This being nullptr is acceptable as V8 will default to its built
+  // in allocator if none is provided
+  page_allocator_ = page_allocator;
   // TODO(addaleax): It's a bit icky that we use global state here, but we can't
   // really do anything about it unless V8 starts exposing a way to access the
   // current v8::Platform instance.
@@ -550,6 +554,10 @@ Platform::StackTracePrinter NodePlatform::GetStackTracePrinter() {
   };
 }
 
+v8::PageAllocator* NodePlatform::GetPageAllocator() {
+  return page_allocator_;
+}
+
 template <class T>
 TaskQueue<T>::TaskQueue()
     : lock_(), tasks_available_(), tasks_drained_(),
diff --git a/src/node_platform.h b/src/node_platform.h
index a7139ebdcc28d24087fb49697a0973331e0387a6..4a05f3bba58c8e875d0ab67f292589edbb3b812b 100644
--- a/src/node_platform.h
+++ b/src/node_platform.h
@@ -138,7 +138,8 @@ class WorkerThreadsTaskRunner {
 class NodePlatform : public MultiIsolatePlatform {
  public:
   NodePlatform(int thread_pool_size,
-               v8::TracingController* tracing_controller);
+               v8::TracingController* tracing_controller,
+               v8::PageAllocator* page_allocator = nullptr);
   ~NodePlatform() override;
 
   void DrainTasks(v8::Isolate* isolate) override;
@@ -170,6 +171,7 @@ class NodePlatform : public MultiIsolatePlatform {
       v8::Isolate* isolate) override;
 
   Platform::StackTracePrinter GetStackTracePrinter() override;
+  v8::PageAllocator* GetPageAllocator() override;
 
  private:
   IsolatePlatformDelegate* ForIsolate(v8::Isolate* isolate);
@@ -181,6 +183,7 @@ class NodePlatform : public MultiIsolatePlatform {
   std::unordered_map<v8::Isolate*, DelegatePair> per_isolate_;
 
   v8::TracingController* tracing_controller_;
+  v8::PageAllocator* page_allocator_;
   std::shared_ptr<WorkerThreadsTaskRunner> worker_thread_task_runner_;
   bool has_shut_down_ = false;
 };
