Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

src: slim down env-inl.h #43745

Merged
merged 1 commit into from
Jul 13, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions src/async_wrap-inl.h
Original file line number Diff line number Diff line change
@@ -80,13 +80,6 @@ inline v8::MaybeLocal<v8::Value> AsyncWrap::MakeCallback(
return MakeCallback(cb_v.As<v8::Function>(), argc, argv);
}


// Defined here to avoid a circular dependency with env-inl.h.
inline AsyncHooks::DefaultTriggerAsyncIdScope ::DefaultTriggerAsyncIdScope(
AsyncWrap* async_wrap)
: DefaultTriggerAsyncIdScope(async_wrap->env(),
async_wrap->get_async_id()) {}

} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
104 changes: 0 additions & 104 deletions src/base_object-inl.h
Original file line number Diff line number Diff line change
@@ -32,40 +32,6 @@

namespace node {

BaseObject::BaseObject(Environment* env, v8::Local<v8::Object> object)
: persistent_handle_(env->isolate(), object), env_(env) {
CHECK_EQ(false, object.IsEmpty());
CHECK_GT(object->InternalFieldCount(), 0);
object->SetAlignedPointerInInternalField(
BaseObject::kSlot,
static_cast<void*>(this));
env->AddCleanupHook(DeleteMe, static_cast<void*>(this));
env->modify_base_object_count(1);
}

BaseObject::~BaseObject() {
env()->modify_base_object_count(-1);
env()->RemoveCleanupHook(DeleteMe, static_cast<void*>(this));

if (UNLIKELY(has_pointer_data())) {
PointerData* metadata = pointer_data();
CHECK_EQ(metadata->strong_ptr_count, 0);
metadata->self = nullptr;
if (metadata->weak_ptr_count == 0)
delete metadata;
}

if (persistent_handle_.IsEmpty()) {
// This most likely happened because the weak callback below cleared it.
return;
}

{
v8::HandleScope handle_scope(env()->isolate());
object()->SetAlignedPointerInInternalField(BaseObject::kSlot, nullptr);
}
}

void BaseObject::Detach() {
CHECK_GT(pointer_data()->strong_ptr_count, 0);
pointer_data()->is_detached = true;
@@ -107,28 +73,6 @@ T* BaseObject::FromJSObject(v8::Local<v8::Value> object) {
return static_cast<T*>(FromJSObject(object));
}


void BaseObject::MakeWeak() {
if (has_pointer_data()) {
pointer_data()->wants_weak_jsobj = true;
if (pointer_data()->strong_ptr_count > 0) return;
}

persistent_handle_.SetWeak(
this,
[](const v8::WeakCallbackInfo<BaseObject>& data) {
BaseObject* obj = data.GetParameter();
// Clear the persistent handle so that ~BaseObject() doesn't attempt
// to mess with internal fields, since the JS object may have
// transitioned into an invalid state.
// Refs: https://github.com/nodejs/node/issues/18897
obj->persistent_handle_.Reset();
CHECK_IMPLIES(obj->has_pointer_data(),
obj->pointer_data()->strong_ptr_count == 0);
obj->OnGCCollect();
}, v8::WeakCallbackType::kParameter);
}

void BaseObject::OnGCCollect() {
delete this;
}
@@ -148,23 +92,6 @@ bool BaseObject::IsWeakOrDetached() const {
return pd->wants_weak_jsobj || pd->is_detached;
}

void BaseObject::LazilyInitializedJSTemplateConstructor(
const v8::FunctionCallbackInfo<v8::Value>& args) {
DCHECK(args.IsConstructCall());
DCHECK_GT(args.This()->InternalFieldCount(), 0);
args.This()->SetAlignedPointerInInternalField(BaseObject::kSlot, nullptr);
}

v8::Local<v8::FunctionTemplate>
BaseObject::MakeLazilyInitializedJSTemplate(Environment* env) {
v8::Local<v8::FunctionTemplate> t =
env->NewFunctionTemplate(LazilyInitializedJSTemplateConstructor);
t->Inherit(BaseObject::GetConstructorTemplate(env));
t->InstanceTemplate()->SetInternalFieldCount(
BaseObject::kInternalFieldCount);
return t;
}

template <int Field>
void BaseObject::InternalFieldGet(
v8::Local<v8::String> property,
@@ -185,37 +112,6 @@ bool BaseObject::has_pointer_data() const {
return pointer_data_ != nullptr;
}

BaseObject::PointerData* BaseObject::pointer_data() {
if (!has_pointer_data()) {
PointerData* metadata = new PointerData();
metadata->wants_weak_jsobj = persistent_handle_.IsWeak();
metadata->self = this;
pointer_data_ = metadata;
}
CHECK(has_pointer_data());
return pointer_data_;
}

void BaseObject::decrease_refcount() {
CHECK(has_pointer_data());
PointerData* metadata = pointer_data();
CHECK_GT(metadata->strong_ptr_count, 0);
unsigned int new_refcount = --metadata->strong_ptr_count;
if (new_refcount == 0) {
if (metadata->is_detached) {
OnGCCollect();
} else if (metadata->wants_weak_jsobj && !persistent_handle_.IsEmpty()) {
MakeWeak();
}
}
}

void BaseObject::increase_refcount() {
unsigned int prev_refcount = pointer_data()->strong_ptr_count++;
if (prev_refcount == 0 && !persistent_handle_.IsEmpty())
persistent_handle_.ClearWeak();
}

template <typename T, bool kIsWeak>
BaseObject::PointerData*
BaseObjectPtrImpl<T, kIsWeak>::pointer_data() const {
16 changes: 8 additions & 8 deletions src/base_object.h
Original file line number Diff line number Diff line change
@@ -44,8 +44,8 @@ class BaseObject : public MemoryRetainer {

// Associates this object with `object`. It uses the 0th internal field for
// that, and in particular aborts if there is no such field.
inline BaseObject(Environment* env, v8::Local<v8::Object> object);
inline ~BaseObject() override;
BaseObject(Environment* env, v8::Local<v8::Object> object);
~BaseObject() override;

BaseObject() = delete;

@@ -65,7 +65,7 @@ class BaseObject : public MemoryRetainer {
// was also passed to the `BaseObject()` constructor initially.
// This may return `nullptr` if the C++ object has not been constructed yet,
// e.g. when the JS object used `MakeLazilyInitializedJSTemplate`.
static inline void LazilyInitializedJSTemplateConstructor(
static void LazilyInitializedJSTemplateConstructor(
const v8::FunctionCallbackInfo<v8::Value>& args);
static inline BaseObject* FromJSObject(v8::Local<v8::Value> object);
template <typename T>
@@ -74,7 +74,7 @@ class BaseObject : public MemoryRetainer {
// Make the `v8::Global` a weak reference and, `delete` this object once
// the JS object has been garbage collected and there are no (strong)
// BaseObjectPtr references to it.
inline void MakeWeak();
void MakeWeak();

// Undo `MakeWeak()`, i.e. turn this into a strong reference that is a GC
// root and will not be touched by the garbage collector.
@@ -88,7 +88,7 @@ class BaseObject : public MemoryRetainer {
// Utility to create a FunctionTemplate with one internal field (used for
// the `BaseObject*` pointer) and a constructor that initializes that field
// to `nullptr`.
static inline v8::Local<v8::FunctionTemplate> MakeLazilyInitializedJSTemplate(
static v8::Local<v8::FunctionTemplate> MakeLazilyInitializedJSTemplate(
Environment* env);

// Setter/Getter pair for internal fields that can be passed to SetAccessor.
@@ -202,11 +202,11 @@ class BaseObject : public MemoryRetainer {
inline bool has_pointer_data() const;
// This creates a PointerData struct if none was associated with this
// BaseObject before.
inline PointerData* pointer_data();
PointerData* pointer_data();

// Functions that adjust the strong pointer count.
inline void decrease_refcount();
inline void increase_refcount();
void decrease_refcount();
void increase_refcount();

Environment* env_;
PointerData* pointer_data_ = nullptr;
389 changes: 0 additions & 389 deletions src/env-inl.h
Original file line number Diff line number Diff line change
@@ -33,7 +33,6 @@
#include "node_perf_common.h"
#include "util-inl.h"
#include "uv.h"
#include "v8-fast-api-calls.h"
#include "v8.h"

#include <cstddef>
@@ -107,24 +106,6 @@ v8::Local<v8::Object> AsyncHooks::native_execution_async_resource(size_t i) {
return native_execution_async_resources_[i];
}

inline void AsyncHooks::SetJSPromiseHooks(v8::Local<v8::Function> init,
v8::Local<v8::Function> before,
v8::Local<v8::Function> after,
v8::Local<v8::Function> resolve) {
js_promise_hooks_[0].Reset(env()->isolate(), init);
js_promise_hooks_[1].Reset(env()->isolate(), before);
js_promise_hooks_[2].Reset(env()->isolate(), after);
js_promise_hooks_[3].Reset(env()->isolate(), resolve);
for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
if (it->IsEmpty()) {
contexts_.erase(it--);
continue;
}
PersistentToLocal::Weak(env()->isolate(), *it)
->SetPromiseHooks(init, before, after, resolve);
}
}

inline v8::Local<v8::String> AsyncHooks::provider_string(int idx) {
return env()->isolate_data()->async_wrap_provider(idx);
}
@@ -137,163 +118,6 @@ inline Environment* AsyncHooks::env() {
return Environment::ForAsyncHooks(this);
}

// Remember to keep this code aligned with pushAsyncContext() in JS.
inline void AsyncHooks::push_async_context(double async_id,
double trigger_async_id,
v8::Local<v8::Object> resource) {
// Since async_hooks is experimental, do only perform the check
// when async_hooks is enabled.
if (fields_[kCheck] > 0) {
CHECK_GE(async_id, -1);
CHECK_GE(trigger_async_id, -1);
}

uint32_t offset = fields_[kStackLength];
if (offset * 2 >= async_ids_stack_.Length())
grow_async_ids_stack();
async_ids_stack_[2 * offset] = async_id_fields_[kExecutionAsyncId];
async_ids_stack_[2 * offset + 1] = async_id_fields_[kTriggerAsyncId];
fields_[kStackLength] += 1;
async_id_fields_[kExecutionAsyncId] = async_id;
async_id_fields_[kTriggerAsyncId] = trigger_async_id;

#ifdef DEBUG
for (uint32_t i = offset; i < native_execution_async_resources_.size(); i++)
CHECK(native_execution_async_resources_[i].IsEmpty());
#endif

// When this call comes from JS (as a way of increasing the stack size),
// `resource` will be empty, because JS caches these values anyway.
if (!resource.IsEmpty()) {
native_execution_async_resources_.resize(offset + 1);
// Caveat: This is a v8::Local<> assignment, we do not keep a v8::Global<>!
native_execution_async_resources_[offset] = resource;
}
}

// Remember to keep this code aligned with popAsyncContext() in JS.
inline bool AsyncHooks::pop_async_context(double async_id) {
// In case of an exception then this may have already been reset, if the
// stack was multiple MakeCallback()'s deep.
if (UNLIKELY(fields_[kStackLength] == 0)) return false;

// Ask for the async_id to be restored as a check that the stack
// hasn't been corrupted.
if (UNLIKELY(fields_[kCheck] > 0 &&
async_id_fields_[kExecutionAsyncId] != async_id)) {
FailWithCorruptedAsyncStack(async_id);
}

uint32_t offset = fields_[kStackLength] - 1;
async_id_fields_[kExecutionAsyncId] = async_ids_stack_[2 * offset];
async_id_fields_[kTriggerAsyncId] = async_ids_stack_[2 * offset + 1];
fields_[kStackLength] = offset;

if (LIKELY(offset < native_execution_async_resources_.size() &&
!native_execution_async_resources_[offset].IsEmpty())) {
#ifdef DEBUG
for (uint32_t i = offset + 1;
i < native_execution_async_resources_.size();
i++) {
CHECK(native_execution_async_resources_[i].IsEmpty());
}
#endif
native_execution_async_resources_.resize(offset);
if (native_execution_async_resources_.size() <
native_execution_async_resources_.capacity() / 2 &&
native_execution_async_resources_.size() > 16) {
native_execution_async_resources_.shrink_to_fit();
}
}

if (UNLIKELY(js_execution_async_resources()->Length() > offset)) {
v8::HandleScope handle_scope(env()->isolate());
USE(js_execution_async_resources()->Set(
env()->context(),
env()->length_string(),
v8::Integer::NewFromUnsigned(env()->isolate(), offset)));
}

return fields_[kStackLength] > 0;
}

void AsyncHooks::clear_async_id_stack() {
v8::Isolate* isolate = env()->isolate();
v8::HandleScope handle_scope(isolate);
if (!js_execution_async_resources_.IsEmpty()) {
USE(PersistentToLocal::Strong(js_execution_async_resources_)->Set(
env()->context(),
env()->length_string(),
v8::Integer::NewFromUnsigned(isolate, 0)));
}
native_execution_async_resources_.clear();
native_execution_async_resources_.shrink_to_fit();

async_id_fields_[kExecutionAsyncId] = 0;
async_id_fields_[kTriggerAsyncId] = 0;
fields_[kStackLength] = 0;
}

inline void AsyncHooks::AddContext(v8::Local<v8::Context> ctx) {
ctx->SetPromiseHooks(
js_promise_hooks_[0].IsEmpty() ?
v8::Local<v8::Function>() :
PersistentToLocal::Strong(js_promise_hooks_[0]),
js_promise_hooks_[1].IsEmpty() ?
v8::Local<v8::Function>() :
PersistentToLocal::Strong(js_promise_hooks_[1]),
js_promise_hooks_[2].IsEmpty() ?
v8::Local<v8::Function>() :
PersistentToLocal::Strong(js_promise_hooks_[2]),
js_promise_hooks_[3].IsEmpty() ?
v8::Local<v8::Function>() :
PersistentToLocal::Strong(js_promise_hooks_[3]));

size_t id = contexts_.size();
contexts_.resize(id + 1);
contexts_[id].Reset(env()->isolate(), ctx);
contexts_[id].SetWeak();
}

inline void AsyncHooks::RemoveContext(v8::Local<v8::Context> ctx) {
v8::Isolate* isolate = env()->isolate();
v8::HandleScope handle_scope(isolate);
contexts_.erase(std::remove_if(contexts_.begin(),
contexts_.end(),
[&](auto&& el) { return el.IsEmpty(); }),
contexts_.end());
for (auto it = contexts_.begin(); it != contexts_.end(); it++) {
v8::Local<v8::Context> saved_context =
PersistentToLocal::Weak(isolate, *it);
if (saved_context == ctx) {
it->Reset();
contexts_.erase(it);
break;
}
}
}

// The DefaultTriggerAsyncIdScope(AsyncWrap*) constructor is defined in
// async_wrap-inl.h to avoid a circular dependency.

inline AsyncHooks::DefaultTriggerAsyncIdScope ::DefaultTriggerAsyncIdScope(
Environment* env, double default_trigger_async_id)
: async_hooks_(env->async_hooks()) {
if (env->async_hooks()->fields()[AsyncHooks::kCheck] > 0) {
CHECK_GE(default_trigger_async_id, 0);
}

old_default_trigger_async_id_ =
async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId];
async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
default_trigger_async_id;
}

inline AsyncHooks::DefaultTriggerAsyncIdScope ::~DefaultTriggerAsyncIdScope() {
async_hooks_->async_id_fields()[AsyncHooks::kDefaultTriggerAsyncId] =
old_default_trigger_async_id_;
}

Environment* Environment::ForAsyncHooks(AsyncHooks* hooks) {
return ContainerOf(&Environment::async_hooks_, hooks);
}
@@ -346,24 +170,6 @@ inline bool TickInfo::has_rejection_to_warn() const {
return fields_[kHasRejectionToWarn] == 1;
}

inline void Environment::AssignToContext(v8::Local<v8::Context> context,
const ContextInfo& info) {
context->SetAlignedPointerInEmbedderData(
ContextEmbedderIndex::kEnvironment, this);
// Used by Environment::GetCurrent to know that we are on a node context.
context->SetAlignedPointerInEmbedderData(
ContextEmbedderIndex::kContextTag, Environment::kNodeContextTagPtr);
// Used to retrieve bindings
context->SetAlignedPointerInEmbedderData(
ContextEmbedderIndex::kBindingListIndex, &(this->bindings_));

#if HAVE_INSPECTOR
inspector_agent()->ContextCreated(context, info);
#endif // HAVE_INSPECTOR

this->async_hooks()->AddContext(context);
}

inline Environment* Environment::GetCurrent(v8::Isolate* isolate) {
if (UNLIKELY(!isolate->InContext())) return nullptr;
v8::HandleScope handle_scope(isolate);
@@ -507,16 +313,6 @@ inline uv_loop_t* Environment::event_loop() const {
return isolate_data()->event_loop();
}

inline void Environment::TryLoadAddon(
const char* filename,
int flags,
const std::function<bool(binding::DLib*)>& was_loaded) {
loaded_addons_.emplace_back(filename, flags);
if (!was_loaded(&loaded_addons_.back())) {
loaded_addons_.pop_back();
}
}

#if HAVE_INSPECTOR
inline bool Environment::is_in_inspector_console_call() const {
return is_in_inspector_console_call_;
@@ -668,22 +464,6 @@ inline const std::string& Environment::exec_path() const {
return exec_path_;
}

inline std::string Environment::GetCwd() {
char cwd[PATH_MAX_BYTES];
size_t size = PATH_MAX_BYTES;
const int err = uv_cwd(cwd, &size);

if (err == 0) {
CHECK_GT(size, 0);
return cwd;
}

// This can fail if the cwd is deleted. In that case, fall back to
// exec_path.
const std::string& exec_path = exec_path_;
return exec_path.substr(0, exec_path.find_last_of(kPathSeparator));
}

#if HAVE_INSPECTOR
inline void Environment::set_coverage_directory(const char* dir) {
coverage_directory_ = std::string(dir);
@@ -938,15 +718,6 @@ inline void Environment::ForEachWorker(Fn&& iterator) {
for (worker::Worker* w : sub_worker_contexts_) iterator(w);
}

inline void Environment::add_refs(int64_t diff) {
task_queues_async_refs_ += diff;
CHECK_GE(task_queues_async_refs_, 0);
if (task_queues_async_refs_ == 0)
uv_unref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
else
uv_ref(reinterpret_cast<uv_handle_t*>(&task_queues_async_));
}

inline bool Environment::is_stopping() const {
return is_stopping_.load();
}
@@ -981,28 +752,6 @@ inline IsolateData* Environment::isolate_data() const {
return isolate_data_;
}

inline uv_buf_t Environment::allocate_managed_buffer(
const size_t suggested_size) {
NoArrayBufferZeroFillScope no_zero_fill_scope(isolate_data());
std::unique_ptr<v8::BackingStore> bs =
v8::ArrayBuffer::NewBackingStore(isolate(), suggested_size);
uv_buf_t buf = uv_buf_init(static_cast<char*>(bs->Data()), bs->ByteLength());
released_allocated_buffers_.emplace(buf.base, std::move(bs));
return buf;
}

inline std::unique_ptr<v8::BackingStore> Environment::release_managed_buffer(
const uv_buf_t& buf) {
std::unique_ptr<v8::BackingStore> bs;
if (buf.base != nullptr) {
auto it = released_allocated_buffers_.find(buf.base);
CHECK_NE(it, released_allocated_buffers_.end());
bs = std::move(it->second);
released_allocated_buffers_.erase(it);
}
return bs;
}

inline void Environment::ThrowError(const char* errmsg) {
ThrowError(v8::Exception::Error, errmsg);
}
@@ -1039,144 +788,6 @@ inline void Environment::ThrowUVException(int errorno,
UVException(isolate(), errorno, syscall, message, path, dest));
}

inline v8::Local<v8::FunctionTemplate> Environment::NewFunctionTemplate(
v8::FunctionCallback callback,
v8::Local<v8::Signature> signature,
v8::ConstructorBehavior behavior,
v8::SideEffectType side_effect_type,
const v8::CFunction* c_function) {
return v8::FunctionTemplate::New(isolate(),
callback,
v8::Local<v8::Value>(),
signature,
0,
behavior,
side_effect_type,
c_function);
}

inline void Environment::SetMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback callback) {
v8::Local<v8::Context> context = isolate()->GetCurrentContext();
v8::Local<v8::Function> function =
NewFunctionTemplate(callback, v8::Local<v8::Signature>(),
v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasSideEffect)
->GetFunction(context)
.ToLocalChecked();
// kInternalized strings are created in the old space.
const v8::NewStringType type = v8::NewStringType::kInternalized;
v8::Local<v8::String> name_string =
v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
that->Set(context, name_string, function).Check();
function->SetName(name_string); // NODE_SET_METHOD() compatibility.
}

inline void Environment::SetFastMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback slow_callback,
const v8::CFunction* c_function) {
v8::Local<v8::Context> context = isolate()->GetCurrentContext();
v8::Local<v8::Function> function =
NewFunctionTemplate(slow_callback,
v8::Local<v8::Signature>(),
v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasNoSideEffect,
c_function)
->GetFunction(context)
.ToLocalChecked();
const v8::NewStringType type = v8::NewStringType::kInternalized;
v8::Local<v8::String> name_string =
v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
that->Set(context, name_string, function).Check();
}

inline void Environment::SetMethodNoSideEffect(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback callback) {
v8::Local<v8::Context> context = isolate()->GetCurrentContext();
v8::Local<v8::Function> function =
NewFunctionTemplate(callback, v8::Local<v8::Signature>(),
v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasNoSideEffect)
->GetFunction(context)
.ToLocalChecked();
// kInternalized strings are created in the old space.
const v8::NewStringType type = v8::NewStringType::kInternalized;
v8::Local<v8::String> name_string =
v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
that->Set(context, name_string, function).Check();
function->SetName(name_string); // NODE_SET_METHOD() compatibility.
}

inline void Environment::SetProtoMethod(v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback) {
v8::Local<v8::Signature> signature = v8::Signature::New(isolate(), that);
v8::Local<v8::FunctionTemplate> t =
NewFunctionTemplate(callback, signature, v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasSideEffect);
// kInternalized strings are created in the old space.
const v8::NewStringType type = v8::NewStringType::kInternalized;
v8::Local<v8::String> name_string =
v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
that->PrototypeTemplate()->Set(name_string, t);
t->SetClassName(name_string); // NODE_SET_PROTOTYPE_METHOD() compatibility.
}

inline void Environment::SetProtoMethodNoSideEffect(
v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback) {
v8::Local<v8::Signature> signature = v8::Signature::New(isolate(), that);
v8::Local<v8::FunctionTemplate> t =
NewFunctionTemplate(callback, signature, v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasNoSideEffect);
// kInternalized strings are created in the old space.
const v8::NewStringType type = v8::NewStringType::kInternalized;
v8::Local<v8::String> name_string =
v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
that->PrototypeTemplate()->Set(name_string, t);
t->SetClassName(name_string); // NODE_SET_PROTOTYPE_METHOD() compatibility.
}

inline void Environment::SetInstanceMethod(v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback) {
v8::Local<v8::Signature> signature = v8::Signature::New(isolate(), that);
v8::Local<v8::FunctionTemplate> t =
NewFunctionTemplate(callback, signature, v8::ConstructorBehavior::kThrow,
v8::SideEffectType::kHasSideEffect);
// kInternalized strings are created in the old space.
const v8::NewStringType type = v8::NewStringType::kInternalized;
v8::Local<v8::String> name_string =
v8::String::NewFromUtf8(isolate(), name, type).ToLocalChecked();
that->InstanceTemplate()->Set(name_string, t);
t->SetClassName(name_string);
}

inline void Environment::SetConstructorFunction(
v8::Local<v8::Object> that,
const char* name,
v8::Local<v8::FunctionTemplate> tmpl,
SetConstructorFunctionFlag flag) {
SetConstructorFunction(that, OneByteString(isolate(), name), tmpl, flag);
}

inline void Environment::SetConstructorFunction(
v8::Local<v8::Object> that,
v8::Local<v8::String> name,
v8::Local<v8::FunctionTemplate> tmpl,
SetConstructorFunctionFlag flag) {
if (LIKELY(flag == SetConstructorFunctionFlag::SET_CLASS_NAME))
tmpl->SetClassName(name);
that->Set(
context(),
name,
tmpl->GetFunction(context()).ToLocalChecked()).Check();
}

void Environment::AddCleanupHook(CleanupCallback fn, void* arg) {
auto insertion_info = cleanup_hooks_.emplace(CleanupHookCallback {
fn, arg, cleanup_hook_counter_++
492 changes: 492 additions & 0 deletions src/env.cc

Large diffs are not rendered by default.

99 changes: 48 additions & 51 deletions src/env.h
Original file line number Diff line number Diff line change
@@ -729,10 +729,10 @@ class AsyncHooks : public MemoryRetainer {
// The `js_execution_async_resources` array contains the value in that case.
inline v8::Local<v8::Object> native_execution_async_resource(size_t index);

inline void SetJSPromiseHooks(v8::Local<v8::Function> init,
v8::Local<v8::Function> before,
v8::Local<v8::Function> after,
v8::Local<v8::Function> resolve);
void SetJSPromiseHooks(v8::Local<v8::Function> init,
v8::Local<v8::Function> before,
v8::Local<v8::Function> after,
v8::Local<v8::Function> resolve);

inline v8::Local<v8::String> provider_string(int idx);

@@ -742,13 +742,14 @@ class AsyncHooks : public MemoryRetainer {
// NB: This call does not take (co-)ownership of `execution_async_resource`.
// The lifetime of the `v8::Local<>` pointee must last until
// `pop_async_context()` or `clear_async_id_stack()` are called.
inline void push_async_context(double async_id, double trigger_async_id,
v8::Local<v8::Object> execution_async_resource);
inline bool pop_async_context(double async_id);
inline void clear_async_id_stack(); // Used in fatal exceptions.
void push_async_context(double async_id,
double trigger_async_id,
v8::Local<v8::Object> execution_async_resource);
bool pop_async_context(double async_id);
void clear_async_id_stack(); // Used in fatal exceptions.

inline void AddContext(v8::Local<v8::Context> ctx);
inline void RemoveContext(v8::Local<v8::Context> ctx);
void AddContext(v8::Local<v8::Context> ctx);
void RemoveContext(v8::Local<v8::Context> ctx);

AsyncHooks(const AsyncHooks&) = delete;
AsyncHooks& operator=(const AsyncHooks&) = delete;
@@ -1128,17 +1129,15 @@ class Environment : public MemoryRetainer {
template <typename T, typename OnCloseCallback>
inline void CloseHandle(T* handle, OnCloseCallback callback);

inline void AssignToContext(v8::Local<v8::Context> context,
const ContextInfo& info);
void AssignToContext(v8::Local<v8::Context> context, const ContextInfo& info);

void StartProfilerIdleNotifier();

inline v8::Isolate* isolate() const;
inline uv_loop_t* event_loop() const;
inline void TryLoadAddon(
const char* filename,
int flags,
const std::function<bool(binding::DLib*)>& was_loaded);
void TryLoadAddon(const char* filename,
int flags,
const std::function<bool(binding::DLib*)>& was_loaded);

static inline Environment* from_timer_handle(uv_timer_t* handle);
inline uv_timer_t* timer_handle();
@@ -1228,7 +1227,7 @@ class Environment : public MemoryRetainer {
// loop alive.
// This is used by Workers to manage their own .ref()/.unref() implementation,
// as Workers aren't directly associated with their own libuv handles.
inline void add_refs(int64_t diff);
void add_refs(int64_t diff);

inline bool has_run_bootstrapping_code() const;
inline void DoneBootstrapping();
@@ -1280,56 +1279,55 @@ class Environment : public MemoryRetainer {
const char* path = nullptr,
const char* dest = nullptr);

inline v8::Local<v8::FunctionTemplate> NewFunctionTemplate(
v8::Local<v8::FunctionTemplate> NewFunctionTemplate(
v8::FunctionCallback callback,
v8::Local<v8::Signature> signature = v8::Local<v8::Signature>(),
v8::ConstructorBehavior behavior = v8::ConstructorBehavior::kAllow,
v8::SideEffectType side_effect = v8::SideEffectType::kHasSideEffect,
const v8::CFunction* c_function = nullptr);

// Convenience methods for NewFunctionTemplate().
inline void SetMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback callback);
void SetMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback callback);

inline void SetFastMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback slow_callback,
const v8::CFunction* c_function);
void SetFastMethod(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback slow_callback,
const v8::CFunction* c_function);

inline void SetProtoMethod(v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback);

inline void SetInstanceMethod(v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback);
void SetProtoMethod(v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback);

void SetInstanceMethod(v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback);

// Safe variants denote the function has no side effects.
inline void SetMethodNoSideEffect(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback callback);
inline void SetProtoMethodNoSideEffect(v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback);
void SetMethodNoSideEffect(v8::Local<v8::Object> that,
const char* name,
v8::FunctionCallback callback);
void SetProtoMethodNoSideEffect(v8::Local<v8::FunctionTemplate> that,
const char* name,
v8::FunctionCallback callback);

enum class SetConstructorFunctionFlag {
NONE,
SET_CLASS_NAME,
};

inline void SetConstructorFunction(v8::Local<v8::Object> that,
const char* name,
v8::Local<v8::FunctionTemplate> tmpl,
SetConstructorFunctionFlag flag =
SetConstructorFunctionFlag::SET_CLASS_NAME);
void SetConstructorFunction(v8::Local<v8::Object> that,
const char* name,
v8::Local<v8::FunctionTemplate> tmpl,
SetConstructorFunctionFlag flag =
SetConstructorFunctionFlag::SET_CLASS_NAME);

inline void SetConstructorFunction(v8::Local<v8::Object> that,
v8::Local<v8::String> name,
v8::Local<v8::FunctionTemplate> tmpl,
SetConstructorFunctionFlag flag =
SetConstructorFunctionFlag::SET_CLASS_NAME);
void SetConstructorFunction(v8::Local<v8::Object> that,
v8::Local<v8::String> name,
v8::Local<v8::FunctionTemplate> tmpl,
SetConstructorFunctionFlag flag =
SetConstructorFunctionFlag::SET_CLASS_NAME);

void AtExit(void (*cb)(void* arg), void* arg);
void RunAtExitCallbacks();
@@ -1487,9 +1485,8 @@ class Environment : public MemoryRetainer {
void RunAndClearNativeImmediates(bool only_refed = false);
void RunAndClearInterrupts();

inline uv_buf_t allocate_managed_buffer(const size_t suggested_size);
inline std::unique_ptr<v8::BackingStore> release_managed_buffer(
const uv_buf_t& buf);
uv_buf_t allocate_managed_buffer(const size_t suggested_size);
std::unique_ptr<v8::BackingStore> release_managed_buffer(const uv_buf_t& buf);

void AddUnmanagedFd(int fd);
void RemoveUnmanagedFd(int fd);