Skip to content

Commit

Permalink
src: add utilities for cppgc classes
Browse files Browse the repository at this point in the history
  • Loading branch information
joyeecheung committed Aug 18, 2024
1 parent 9e83853 commit 0c7e2a5
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 9 deletions.
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@
'src/compile_cache.h',
'src/connect_wrap.h',
'src/connection_wrap.h',
'src/cppgc_helpers.h',
'src/dataqueue/queue.h',
'src/debug_utils.h',
'src/debug_utils-inl.h',
Expand Down
81 changes: 81 additions & 0 deletions src/cppgc_helpers.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#ifndef SRC_CPPGC_HELPERS_H_
#define SRC_CPPGC_HELPERS_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include <type_traits> // std::remove_reference
#include "cppgc/garbage-collected.h"
#include "cppgc/name-provider.h"
#include "env.h"
#include "memory_tracker.h"
#include "v8-cppgc.h"
#include "v8.h"

namespace node {

#define ASSIGN_OR_RETURN_UNWRAP_CPPGC(ptr, obj, ...) \
do { \
*ptr = CppgcMixin::Unwrap< \
typename std::remove_reference<decltype(**ptr)>::type>(obj); \
if (*ptr == nullptr) return __VA_ARGS__; \
} while (0)

// TODO(joyeecheung): make it a class template?
class CppgcMixin : public cppgc::GarbageCollectedMixin {
public:
enum InternalFields { kEmbedderType = 0, kSlot, kInternalFieldCount };

// This must not be a constructor but called in the child class constructor,
// per cppgc::GarbageCollectedMixin rules.
template <typename T>
void InitializeCppgc(T* ptr, Environment* env, v8::Local<v8::Object> obj) {
env_ = env;
traced_reference_ = v8::TracedReference<v8::Object>(env->isolate(), obj);
SetCppgcReference(env->isolate(), obj, ptr);
// We are adding this additional slot to that BaseObject and cppgc-managed
// objects share the same layout.
CHECK_GE(obj->InternalFieldCount(), T::kInternalFieldCount);
obj->SetAlignedPointerInInternalField(T::kSlot, ptr);
}

v8::Local<v8::Object> object() const {
return traced_reference_.Get(env_->isolate());
}

Environment* env() const { return env_; }

template <typename T>
static T* Unwrap(v8::Local<v8::Object> obj) {
// We are not using v8::Object::Unwrap currently because that requires
// access to isolate which the ASSIGN_OR_RETURN_UNWRAP macro that we'll shim
// with cppgc-allocated types doesn't take.
if (obj->InternalFieldCount() != T::kInternalFieldCount) {
return nullptr;
}
T* ptr = static_cast<T*>(obj->GetAlignedPointerFromInternalField(T::kSlot));
return ptr;
}

void Trace(cppgc::Visitor* visitor) const override {
visitor->Trace(traced_reference_);
}

private:
Environment* env_;
v8::TracedReference<v8::Object> traced_reference_;
};

#define DEFAULT_CPPGC_TRACE() \
void Trace(cppgc::Visitor* visitor) const final { \
CppgcMixin::Trace(visitor); \
}

#define SET_CPPGC_NAME(Klass) \
inline const char* GetHumanReadableName() const final { \
return "Node / " #Klass; \
}
} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#endif // SRC_BASE_OBJECT_H_
34 changes: 25 additions & 9 deletions src/heap_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using v8::Array;
using v8::Boolean;
using v8::Context;
using v8::Data;
using v8::EmbedderGraph;
using v8::EscapableHandleScope;
using v8::FunctionCallbackInfo;
Expand Down Expand Up @@ -50,18 +51,20 @@ class JSGraphJSNode : public EmbedderGraph::Node {
const char* Name() override { return "<JS Node>"; }
size_t SizeInBytes() override { return 0; }
bool IsEmbedderNode() override { return false; }
Local<Value> JSValue() { return PersistentToLocal::Strong(persistent_); }
Local<Data> V8Value() { return PersistentToLocal::Strong(persistent_); }

int IdentityHash() {
Local<Value> v = JSValue();
Local<Data> d = V8Value();
// TODO(joyeecheung): return something better?
if (!d->IsValue()) return reinterpret_cast<std::uintptr_t>(this);
Local<Value> v = d.As<Value>();
if (v->IsObject()) return v.As<Object>()->GetIdentityHash();
if (v->IsName()) return v.As<v8::Name>()->GetIdentityHash();
if (v->IsInt32()) return v.As<v8::Int32>()->Value();
return 0;
}

JSGraphJSNode(Isolate* isolate, Local<Value> val)
: persistent_(isolate, val) {
JSGraphJSNode(Isolate* isolate, Local<Data> val) : persistent_(isolate, val) {
CHECK(!val.IsEmpty());
}

Expand All @@ -73,19 +76,27 @@ class JSGraphJSNode : public EmbedderGraph::Node {

struct Equal {
inline bool operator()(JSGraphJSNode* a, JSGraphJSNode* b) const {
return a->JSValue()->SameValue(b->JSValue());
Local<Data> data_a = a->V8Value();
Local<Data> data_b = a->V8Value();
if (data_a->IsValue()) {
if (!data_b->IsValue()) {
return false;
}
return data_a.As<Value>()->SameValue(data_b.As<Value>());
}
return data_a == data_b;
}
};

private:
Global<Value> persistent_;
Global<Data> persistent_;
};

class JSGraph : public EmbedderGraph {
public:
explicit JSGraph(Isolate* isolate) : isolate_(isolate) {}

Node* V8Node(const Local<Value>& value) override {
Node* V8Node(const Local<v8::Data>& value) override {
std::unique_ptr<JSGraphJSNode> n { new JSGraphJSNode(isolate_, value) };
auto it = engine_nodes_.find(n.get());
if (it != engine_nodes_.end())
Expand All @@ -94,6 +105,10 @@ class JSGraph : public EmbedderGraph {
return AddNode(std::unique_ptr<Node>(n.release()));
}

Node* V8Node(const Local<v8::Value>& value) override {
return V8Node(value.As<v8::Data>());
}

Node* AddNode(std::unique_ptr<Node> node) override {
Node* n = node.get();
nodes_.emplace(std::move(node));
Expand Down Expand Up @@ -154,8 +169,9 @@ class JSGraph : public EmbedderGraph {
if (nodes->Set(context, i++, obj).IsNothing())
return MaybeLocal<Array>();
if (!n->IsEmbedderNode()) {
value = static_cast<JSGraphJSNode*>(n.get())->JSValue();
if (obj->Set(context, value_string, value).IsNothing())
Local<Data> data = static_cast<JSGraphJSNode*>(n.get())->V8Value();
if (data->IsValue() &&
obj->Set(context, value_string, data.As<Value>()).IsNothing())
return MaybeLocal<Array>();
}
}
Expand Down
24 changes: 24 additions & 0 deletions src/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,30 @@ void SetConstructorFunction(v8::Isolate* isolate,
SetConstructorFunctionFlag flag =
SetConstructorFunctionFlag::SET_CLASS_NAME);

#define GET_OR_SET_CONSTRUCTOR_TEMPLATE(tmpl, isolate_data, id, name) \
do { \
v8::Isolate* isolate = isolate_data->isolate(); \
tmpl = isolate_data->id##_constructor_template(); \
if (tmpl.IsEmpty()) { \
tmpl = v8::FunctionTemplate::New(isolate, New); \
tmpl->InstanceTemplate()->SetInternalFieldCount(kInternalFieldCount); \
tmpl->SetClassName(FIXED_ONE_BYTE_STRING(isolate, #name)); \
isolate_data->set_##id##_constructor_template(tmpl); \
} \
} while (0);

#define CONSTRUCTOR_TEMPLATE_GENERATOR(id, name) \
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate( \
IsolateData* isolate_data) { \
v8::Local<v8::FunctionTemplate> tmpl; \
GET_OR_SET_CONSTRUCTOR_TEMPLATE(tmpl, isolate_data, id, name); \
return tmpl; \
}

#define DECL_CONSTRUCTOR_TEMPLATE_GENERATOR() \
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate( \
IsolateData* isolate_data);

// Like RAIIIsolate, except doesn't enter the isolate while it's in scope.
class RAIIIsolateWithoutEntering {
public:
Expand Down

0 comments on commit 0c7e2a5

Please sign in to comment.