src_remove_dependency_on_wrapper-descriptor-based_cppheap.patch 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
  2. From: Joyee Cheung <[email protected]>
  3. Date: Wed, 29 May 2024 19:59:19 +0200
  4. Subject: src: remove dependency on wrapper-descriptor-based CppHeap
  5. As V8 has moved away from wrapper-descriptor-based CppHeap, this
  6. patch:
  7. 1. Create the CppHeap without using wrapper descirptors.
  8. 2. Deprecates node::SetCppgcReference() in favor of
  9. v8::Object::Wrap() since the wrapper descriptor is no longer
  10. relevant. It is still kept as a compatibility layer for addons
  11. that need to also work on Node.js versions without
  12. v8::Object::Wrap().
  13. (cherry picked from commit 30329d06235a9f9733b1d4da479b403462d1b326)
  14. diff --git a/src/env-inl.h b/src/env-inl.h
  15. index 63ce35ba68b48a55d8150395304bf86c2bf23aae..c6fc53d1666ae51e69257c9bbcaf4cbff36cbad3 100644
  16. --- a/src/env-inl.h
  17. +++ b/src/env-inl.h
  18. @@ -62,31 +62,6 @@ inline uv_loop_t* IsolateData::event_loop() const {
  19. return event_loop_;
  20. }
  21. -inline void IsolateData::SetCppgcReference(v8::Isolate* isolate,
  22. - v8::Local<v8::Object> object,
  23. - void* wrappable) {
  24. - v8::CppHeap* heap = isolate->GetCppHeap();
  25. - CHECK_NOT_NULL(heap);
  26. - v8::WrapperDescriptor descriptor = heap->wrapper_descriptor();
  27. - uint16_t required_size = std::max(descriptor.wrappable_instance_index,
  28. - descriptor.wrappable_type_index);
  29. - CHECK_GT(object->InternalFieldCount(), required_size);
  30. -
  31. - uint16_t* id_ptr = nullptr;
  32. - {
  33. - Mutex::ScopedLock lock(isolate_data_mutex_);
  34. - auto it =
  35. - wrapper_data_map_.find(descriptor.embedder_id_for_garbage_collected);
  36. - CHECK_NE(it, wrapper_data_map_.end());
  37. - id_ptr = &(it->second->cppgc_id);
  38. - }
  39. -
  40. - object->SetAlignedPointerInInternalField(descriptor.wrappable_type_index,
  41. - id_ptr);
  42. - object->SetAlignedPointerInInternalField(descriptor.wrappable_instance_index,
  43. - wrappable);
  44. -}
  45. -
  46. inline uint16_t* IsolateData::embedder_id_for_cppgc() const {
  47. return &(wrapper_data_->cppgc_id);
  48. }
  49. diff --git a/src/env.cc b/src/env.cc
  50. index 7bd5edf61c339daa1e1b0df8e2e91680948641de..b75f3d11054a656ac0acadea27cd183d71b5d90f 100644
  51. --- a/src/env.cc
  52. +++ b/src/env.cc
  53. @@ -22,6 +22,7 @@
  54. #include "util-inl.h"
  55. #include "v8-cppgc.h"
  56. #include "v8-profiler.h"
  57. +#include "v8-sandbox.h" // v8::Object::Wrap(), v8::Object::Unwrap()
  58. #include <algorithm>
  59. #include <atomic>
  60. @@ -68,7 +69,6 @@ using v8::TryCatch;
  61. using v8::Uint32;
  62. using v8::Undefined;
  63. using v8::Value;
  64. -using v8::WrapperDescriptor;
  65. using worker::Worker;
  66. int const ContextEmbedderTag::kNodeContextTag = 0x6e6f64;
  67. @@ -518,6 +518,14 @@ void IsolateData::CreateProperties() {
  68. CreateEnvProxyTemplate(this);
  69. }
  70. +// Previously, the general convention of the wrappable layout for cppgc in
  71. +// the ecosystem is:
  72. +// [ 0 ] -> embedder id
  73. +// [ 1 ] -> wrappable instance
  74. +// Now V8 has deprecated this layout-based tracing enablement, embedders
  75. +// should simply use v8::Object::Wrap() and v8::Object::Unwrap(). We preserve
  76. +// this layout only to distinguish internally how the memory of a Node.js
  77. +// wrapper is managed or whether a wrapper is managed by Node.js.
  78. constexpr uint16_t kDefaultCppGCEmebdderID = 0x90de;
  79. Mutex IsolateData::isolate_data_mutex_;
  80. std::unordered_map<uint16_t, std::unique_ptr<PerIsolateWrapperData>>
  81. @@ -539,36 +547,16 @@ IsolateData::IsolateData(Isolate* isolate,
  82. v8::CppHeap* cpp_heap = isolate->GetCppHeap();
  83. uint16_t cppgc_id = kDefaultCppGCEmebdderID;
  84. - if (cpp_heap != nullptr) {
  85. - // The general convention of the wrappable layout for cppgc in the
  86. - // ecosystem is:
  87. - // [ 0 ] -> embedder id
  88. - // [ 1 ] -> wrappable instance
  89. - // If the Isolate includes a CppHeap attached by another embedder,
  90. - // And if they also use the field 0 for the ID, we DCHECK that
  91. - // the layout matches our layout, and record the embedder ID for cppgc
  92. - // to avoid accidentally enabling cppgc on non-cppgc-managed wrappers .
  93. - v8::WrapperDescriptor descriptor = cpp_heap->wrapper_descriptor();
  94. - if (descriptor.wrappable_type_index == BaseObject::kEmbedderType) {
  95. - cppgc_id = descriptor.embedder_id_for_garbage_collected;
  96. - DCHECK_EQ(descriptor.wrappable_instance_index, BaseObject::kSlot);
  97. - }
  98. - // If the CppHeap uses the slot we use to put non-cppgc-traced BaseObject
  99. - // for embedder ID, V8 could accidentally enable cppgc on them. So
  100. - // safe guard against this.
  101. - DCHECK_NE(descriptor.wrappable_type_index, BaseObject::kSlot);
  102. - } else {
  103. - cpp_heap_ = CppHeap::Create(
  104. - platform,
  105. - CppHeapCreateParams{
  106. - {},
  107. - WrapperDescriptor(
  108. - BaseObject::kEmbedderType, BaseObject::kSlot, cppgc_id)});
  109. - isolate->AttachCppHeap(cpp_heap_.get());
  110. - }
  111. // We do not care about overflow since we just want this to be different
  112. // from the cppgc id.
  113. uint16_t non_cppgc_id = cppgc_id + 1;
  114. + if (cpp_heap == nullptr) {
  115. + cpp_heap_ = CppHeap::Create(platform, v8::CppHeapCreateParams{{}});
  116. + // TODO(joyeecheung): pass it into v8::Isolate::CreateParams and let V8
  117. + // own it when we can keep the isolate registered/task runner discoverable
  118. + // during isolate disposal.
  119. + isolate->AttachCppHeap(cpp_heap_.get());
  120. + }
  121. {
  122. // GC could still be run after the IsolateData is destroyed, so we store
  123. @@ -600,11 +588,12 @@ IsolateData::~IsolateData() {
  124. }
  125. }
  126. -// Public API
  127. +// Deprecated API, embedders should use v8::Object::Wrap() directly instead.
  128. void SetCppgcReference(Isolate* isolate,
  129. Local<Object> object,
  130. void* wrappable) {
  131. - IsolateData::SetCppgcReference(isolate, object, wrappable);
  132. + v8::Object::Wrap<v8::CppHeapPointerTag::kDefaultTag>(
  133. + isolate, object, wrappable);
  134. }
  135. void IsolateData::MemoryInfo(MemoryTracker* tracker) const {
  136. diff --git a/src/env.h b/src/env.h
  137. index 910c69b6d1d17ef25201dbb39d3d074f4f3f011f..5fd375f143dd529c83aca59348182cce47d3abf8 100644
  138. --- a/src/env.h
  139. +++ b/src/env.h
  140. @@ -164,10 +164,6 @@ class NODE_EXTERN_PRIVATE IsolateData : public MemoryRetainer {
  141. uint16_t* embedder_id_for_cppgc() const;
  142. uint16_t* embedder_id_for_non_cppgc() const;
  143. - static inline void SetCppgcReference(v8::Isolate* isolate,
  144. - v8::Local<v8::Object> object,
  145. - void* wrappable);
  146. -
  147. inline uv_loop_t* event_loop() const;
  148. inline MultiIsolatePlatform* platform() const;
  149. inline const SnapshotData* snapshot_data() const;
  150. diff --git a/src/node.h b/src/node.h
  151. index e55256996f2c85b0ae3854cbd1b83ca88a3e22cb..5aa647a095ed965a3f7e755947be4948c75651d6 100644
  152. --- a/src/node.h
  153. +++ b/src/node.h
  154. @@ -1557,24 +1557,14 @@ void RegisterSignalHandler(int signal,
  155. bool reset_handler = false);
  156. #endif // _WIN32
  157. -// Configure the layout of the JavaScript object with a cppgc::GarbageCollected
  158. -// instance so that when the JavaScript object is reachable, the garbage
  159. -// collected instance would have its Trace() method invoked per the cppgc
  160. -// contract. To make it work, the process must have called
  161. -// cppgc::InitializeProcess() before, which is usually the case for addons
  162. -// loaded by the stand-alone Node.js executable. Embedders of Node.js can use
  163. -// either need to call it themselves or make sure that
  164. -// ProcessInitializationFlags::kNoInitializeCppgc is *not* set for cppgc to
  165. -// work.
  166. -// If the CppHeap is owned by Node.js, which is usually the case for addon,
  167. -// the object must be created with at least two internal fields available,
  168. -// and the first two internal fields would be configured by Node.js.
  169. -// This may be superseded by a V8 API in the future, see
  170. -// https://bugs.chromium.org/p/v8/issues/detail?id=13960. Until then this
  171. -// serves as a helper for Node.js isolates.
  172. -NODE_EXTERN void SetCppgcReference(v8::Isolate* isolate,
  173. - v8::Local<v8::Object> object,
  174. - void* wrappable);
  175. +// This is kept as a compatibility layer for addons to wrap cppgc-managed
  176. +// objects on Node.js versions without v8::Object::Wrap(). Addons created to
  177. +// work with only Node.js versions with v8::Object::Wrap() should use that
  178. +// instead.
  179. +NODE_DEPRECATED("Use v8::Object::Wrap()",
  180. + NODE_EXTERN void SetCppgcReference(v8::Isolate* isolate,
  181. + v8::Local<v8::Object> object,
  182. + void* wrappable));
  183. } // namespace node
  184. diff --git a/test/addons/cppgc-object/binding.cc b/test/addons/cppgc-object/binding.cc
  185. index 1b70ff11dc561abdc5ac794f6280557d5c428239..7fc16a87b843ce0626ee137a07c3ccb7f4cc6493 100644
  186. --- a/test/addons/cppgc-object/binding.cc
  187. +++ b/test/addons/cppgc-object/binding.cc
  188. @@ -1,8 +1,10 @@
  189. +#include <assert.h>
  190. #include <cppgc/allocation.h>
  191. #include <cppgc/garbage-collected.h>
  192. #include <cppgc/heap.h>
  193. #include <node.h>
  194. #include <v8-cppgc.h>
  195. +#include <v8-sandbox.h>
  196. #include <v8.h>
  197. #include <algorithm>
  198. @@ -15,8 +17,10 @@ class CppGCed : public cppgc::GarbageCollected<CppGCed> {
  199. static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
  200. v8::Isolate* isolate = args.GetIsolate();
  201. v8::Local<v8::Object> js_object = args.This();
  202. - CppGCed* gc_object = cppgc::MakeGarbageCollected<CppGCed>(
  203. - isolate->GetCppHeap()->GetAllocationHandle());
  204. + auto* heap = isolate->GetCppHeap();
  205. + assert(heap != nullptr);
  206. + CppGCed* gc_object =
  207. + cppgc::MakeGarbageCollected<CppGCed>(heap->GetAllocationHandle());
  208. node::SetCppgcReference(isolate, js_object, gc_object);
  209. args.GetReturnValue().Set(js_object);
  210. }
  211. @@ -24,12 +28,6 @@ class CppGCed : public cppgc::GarbageCollected<CppGCed> {
  212. static v8::Local<v8::Function> GetConstructor(
  213. v8::Local<v8::Context> context) {
  214. auto ft = v8::FunctionTemplate::New(context->GetIsolate(), New);
  215. - auto ot = ft->InstanceTemplate();
  216. - v8::WrapperDescriptor descriptor =
  217. - context->GetIsolate()->GetCppHeap()->wrapper_descriptor();
  218. - uint16_t required_size = std::max(descriptor.wrappable_instance_index,
  219. - descriptor.wrappable_type_index);
  220. - ot->SetInternalFieldCount(required_size + 1);
  221. return ft->GetFunction(context).ToLocalChecked();
  222. }
  223. diff --git a/test/cctest/test_cppgc.cc b/test/cctest/test_cppgc.cc
  224. index 49665174615870b4f70529b1d548e593846140a1..edd413ae9b956b2e59e8166785adef6a8ff06d51 100644
  225. --- a/test/cctest/test_cppgc.cc
  226. +++ b/test/cctest/test_cppgc.cc
  227. @@ -3,16 +3,12 @@
  228. #include <cppgc/heap.h>
  229. #include <node.h>
  230. #include <v8-cppgc.h>
  231. +#include <v8-sandbox.h>
  232. #include <v8.h>
  233. #include "node_test_fixture.h"
  234. // This tests that Node.js can work with an existing CppHeap.
  235. -// Mimic the Blink layout.
  236. -static int kWrappableTypeIndex = 0;
  237. -static int kWrappableInstanceIndex = 1;
  238. -static uint16_t kEmbedderID = 0x1;
  239. -
  240. // Mimic a class that does not know about Node.js.
  241. class CppGCed : public cppgc::GarbageCollected<CppGCed> {
  242. public:
  243. @@ -23,12 +19,11 @@ class CppGCed : public cppgc::GarbageCollected<CppGCed> {
  244. static void New(const v8::FunctionCallbackInfo<v8::Value>& args) {
  245. v8::Isolate* isolate = args.GetIsolate();
  246. v8::Local<v8::Object> js_object = args.This();
  247. - CppGCed* gc_object = cppgc::MakeGarbageCollected<CppGCed>(
  248. - isolate->GetCppHeap()->GetAllocationHandle());
  249. - js_object->SetAlignedPointerInInternalField(kWrappableTypeIndex,
  250. - &kEmbedderID);
  251. - js_object->SetAlignedPointerInInternalField(kWrappableInstanceIndex,
  252. - gc_object);
  253. + auto* heap = isolate->GetCppHeap();
  254. + CHECK_NOT_NULL(heap);
  255. + CppGCed* gc_object =
  256. + cppgc::MakeGarbageCollected<CppGCed>(heap->GetAllocationHandle());
  257. + node::SetCppgcReference(isolate, js_object, gc_object);
  258. kConstructCount++;
  259. args.GetReturnValue().Set(js_object);
  260. }
  261. @@ -36,8 +31,6 @@ class CppGCed : public cppgc::GarbageCollected<CppGCed> {
  262. static v8::Local<v8::Function> GetConstructor(
  263. v8::Local<v8::Context> context) {
  264. auto ft = v8::FunctionTemplate::New(context->GetIsolate(), New);
  265. - auto ot = ft->InstanceTemplate();
  266. - ot->SetInternalFieldCount(2);
  267. return ft->GetFunction(context).ToLocalChecked();
  268. }
  269. @@ -58,12 +51,12 @@ TEST_F(NodeZeroIsolateTestFixture, ExistingCppHeapTest) {
  270. // Create and attach the CppHeap before we set up the IsolateData so that
  271. // it recognizes the existing heap.
  272. - std::unique_ptr<v8::CppHeap> cpp_heap = v8::CppHeap::Create(
  273. - platform.get(),
  274. - v8::CppHeapCreateParams(
  275. - {},
  276. - v8::WrapperDescriptor(
  277. - kWrappableTypeIndex, kWrappableInstanceIndex, kEmbedderID)));
  278. + std::unique_ptr<v8::CppHeap> cpp_heap =
  279. + v8::CppHeap::Create(platform.get(), v8::CppHeapCreateParams{{}});
  280. +
  281. + // TODO(joyeecheung): pass it into v8::Isolate::CreateParams and let V8
  282. + // own it when we can keep the isolate registered/task runner discoverable
  283. + // during isolate disposal.
  284. isolate->AttachCppHeap(cpp_heap.get());
  285. // Try creating Context + IsolateData + Environment.