From f4c2dff4e61570e6b8512f2a41ac2d17c2473a5e Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Tue, 5 Mar 2019 03:02:57 +0100 Subject: [PATCH] src: move fs state out of Environment Moves state that is specific to the `fs` binding into the `fs` binding implementation as a cleanup. PR-URL: https://github.com/nodejs/node/pull/32538 Reviewed-By: James M Snell --- src/env-inl.h | 13 ---- src/env.cc | 14 +--- src/env.h | 16 ----- src/node_dir.cc | 6 +- src/node_file-inl.h | 57 ++++++++++------ src/node_file.cc | 139 ++++++++++++++++++++++----------------- src/node_file.h | 48 +++++++++++--- src/node_stat_watcher.cc | 19 +++--- src/node_stat_watcher.h | 6 +- 9 files changed, 175 insertions(+), 143 deletions(-) diff --git a/src/env-inl.h b/src/env-inl.h index a2c26b182bb203..f681a0bf1d8dcc 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -580,19 +580,6 @@ inline double Environment::get_default_trigger_async_id() { return default_trigger_async_id; } -inline AliasedFloat64Array* Environment::fs_stats_field_array() { - return &fs_stats_field_array_; -} - -inline AliasedBigUint64Array* Environment::fs_stats_field_bigint_array() { - return &fs_stats_field_bigint_array_; -} - -inline std::vector>& -Environment::file_handle_read_wrap_freelist() { - return file_handle_read_wrap_freelist_; -} - inline std::shared_ptr Environment::options() { return options_; } diff --git a/src/env.cc b/src/env.cc index 17b607995550c8..36f8d42b86dc9b 100644 --- a/src/env.cc +++ b/src/env.cc @@ -1,18 +1,19 @@ #include "env.h" #include "async_wrap.h" +#include "base_object-inl.h" #include "debug_utils-inl.h" #include "memory_tracker-inl.h" #include "node_buffer.h" #include "node_context_data.h" #include "node_errors.h" -#include "node_file.h" #include "node_internals.h" #include "node_options-inl.h" #include "node_process.h" #include "node_v8_platform-inl.h" #include "node_worker.h" #include "req_wrap-inl.h" +#include "stream_base.h" #include "tracing/agent.h" #include "tracing/traced_value.h" #include "util-inl.h" @@ -341,8 +342,6 @@ Environment::Environment(IsolateData* isolate_data, flags_(flags), thread_id_(thread_id.id == static_cast(-1) ? AllocateEnvironmentThreadId().id : thread_id.id), - fs_stats_field_array_(isolate_, kFsStatsBufferLength), - fs_stats_field_bigint_array_(isolate_, kFsStatsBufferLength), context_(context->GetIsolate(), context) { // We'll be creating new objects so make sure we've entered the context. HandleScope handle_scope(isolate()); @@ -444,10 +443,6 @@ Environment::~Environment() { isolate()->GetHeapProfiler()->RemoveBuildEmbedderGraphCallback( BuildEmbedderGraph, this); - // Make sure there are no re-used libuv wrapper objects. - // CleanupHandles() should have removed all of them. - CHECK(file_handle_read_wrap_freelist_.empty()); - HandleScope handle_scope(isolate()); #if HAVE_INSPECTOR @@ -613,8 +608,6 @@ void Environment::CleanupHandles() { !handle_wrap_queue_.IsEmpty()) { uv_run(event_loop(), UV_RUN_ONCE); } - - file_handle_read_wrap_freelist_.clear(); } void Environment::StartProfilerIdleNotifier() { @@ -1096,9 +1089,6 @@ void Environment::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackField("should_abort_on_uncaught_toggle", should_abort_on_uncaught_toggle_); tracker->TrackField("stream_base_state", stream_base_state_); - tracker->TrackField("fs_stats_field_array", fs_stats_field_array_); - tracker->TrackField("fs_stats_field_bigint_array", - fs_stats_field_bigint_array_); tracker->TrackField("cleanup_hooks", cleanup_hooks_); tracker->TrackField("async_hooks", async_hooks_); tracker->TrackField("immediate_info", immediate_info_); diff --git a/src/env.h b/src/env.h index 4303c56916720e..539fbf19f4a496 100644 --- a/src/env.h +++ b/src/env.h @@ -56,10 +56,6 @@ class ContextifyScript; class CompiledFnEntry; } -namespace fs { -class FileHandleReadWrap; -} - namespace performance { class PerformanceState; } @@ -1009,12 +1005,6 @@ class Environment : public MemoryRetainer { EnabledDebugList* enabled_debug_list() { return &enabled_debug_list_; } - inline AliasedFloat64Array* fs_stats_field_array(); - inline AliasedBigUint64Array* fs_stats_field_bigint_array(); - - inline std::vector>& - file_handle_read_wrap_freelist(); - inline performance::PerformanceState* performance_state(); inline std::unordered_map* performance_marks(); @@ -1365,12 +1355,6 @@ class Environment : public MemoryRetainer { EnabledDebugList enabled_debug_list_; - AliasedFloat64Array fs_stats_field_array_; - AliasedBigUint64Array fs_stats_field_bigint_array_; - - std::vector> - file_handle_read_wrap_freelist_; - std::list extra_linked_bindings_; Mutex extra_linked_bindings_mutex_; diff --git a/src/node_dir.cc b/src/node_dir.cc index 9923f042779f2e..c4aaf4bcd3e8ba 100644 --- a/src/node_dir.cc +++ b/src/node_dir.cc @@ -152,7 +152,7 @@ void DirHandle::Close(const FunctionCallbackInfo& args) { dir->closing_ = false; dir->closed_ = true; - FSReqBase* req_wrap_async = GetReqWrap(env, args[0]); + FSReqBase* req_wrap_async = GetReqWrap(args, 0); if (req_wrap_async != nullptr) { // close(req) AsyncCall(env, req_wrap_async, args, "closedir", UTF8, AfterClose, uv_fs_closedir, dir->dir()); @@ -252,7 +252,7 @@ void DirHandle::Read(const FunctionCallbackInfo& args) { dir->dir_->dirents = dir->dirents_.data(); } - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { // dir.read(encoding, bufferSize, req) AsyncCall(env, req_wrap_async, args, "readdir", encoding, AfterDirRead, uv_fs_readdir, dir->dir()); @@ -320,7 +320,7 @@ static void OpenDir(const FunctionCallbackInfo& args) { const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { // openDir(path, encoding, req) AsyncCall(env, req_wrap_async, args, "opendir", encoding, AfterOpenDir, uv_fs_opendir, *path); diff --git a/src/node_file-inl.h b/src/node_file-inl.h index e9ed18a75fa48b..d30d77301005a3 100644 --- a/src/node_file-inl.h +++ b/src/node_file-inl.h @@ -39,11 +39,13 @@ void FSContinuationData::Done(int result) { done_cb_(req_); } -FSReqBase::FSReqBase(Environment* env, - v8::Local req, - AsyncWrap::ProviderType type, - bool use_bigint) - : ReqWrap(env, req, type), use_bigint_(use_bigint) { +FSReqBase::FSReqBase(BindingData* binding_data, + v8::Local req, + AsyncWrap::ProviderType type, + bool use_bigint) + : ReqWrap(binding_data->env(), req, type), + use_bigint_(use_bigint), + binding_data_(binding_data) { } void FSReqBase::Init(const char* syscall, @@ -72,9 +74,13 @@ FSReqBase::Init(const char* syscall, size_t len, enum encoding encoding) { return buffer_; } -FSReqCallback::FSReqCallback(Environment* env, - v8::Local req, bool use_bigint) - : FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQCALLBACK, use_bigint) {} +FSReqCallback::FSReqCallback(BindingData* binding_data, + v8::Local req, + bool use_bigint) + : FSReqBase(binding_data, + req, + AsyncWrap::PROVIDER_FSREQCALLBACK, + use_bigint) {} template void FillStatsArray(AliasedBufferBase* fields, @@ -112,18 +118,18 @@ void FillStatsArray(AliasedBufferBase* fields, #undef SET_FIELD_WITH_STAT } -v8::Local FillGlobalStatsArray(Environment* env, +v8::Local FillGlobalStatsArray(BindingData* binding_data, const bool use_bigint, const uv_stat_t* s, const bool second) { const ptrdiff_t offset = second ? static_cast(FsStatsOffset::kFsStatsFieldsNumber) : 0; if (use_bigint) { - auto* const arr = env->fs_stats_field_bigint_array(); + auto* const arr = &binding_data->stats_field_bigint_array; FillStatsArray(arr, s, offset); return arr->GetJSArray(); } else { - auto* const arr = env->fs_stats_field_array(); + auto* const arr = &binding_data->stats_field_array; FillStatsArray(arr, s, offset); return arr->GetJSArray(); } @@ -131,7 +137,9 @@ v8::Local FillGlobalStatsArray(Environment* env, template FSReqPromise* -FSReqPromise::New(Environment* env, bool use_bigint) { +FSReqPromise::New(BindingData* binding_data, + bool use_bigint) { + Environment* env = binding_data->env(); v8::Local obj; if (!env->fsreqpromise_constructor_template() ->NewInstance(env->context()) @@ -143,7 +151,7 @@ FSReqPromise::New(Environment* env, bool use_bigint) { obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) { return nullptr; } - return new FSReqPromise(env, obj, use_bigint); + return new FSReqPromise(binding_data, obj, use_bigint); } template @@ -154,12 +162,15 @@ FSReqPromise::~FSReqPromise() { template FSReqPromise::FSReqPromise( - Environment* env, + BindingData* binding_data, v8::Local obj, bool use_bigint) - : FSReqBase(env, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint), + : FSReqBase(binding_data, + obj, + AsyncWrap::PROVIDER_FSREQPROMISE, + use_bigint), stats_field_array_( - env->isolate(), + env()->isolate(), static_cast(FsStatsOffset::kFsStatsFieldsNumber)) {} template @@ -208,15 +219,21 @@ void FSReqPromise::MemoryInfo(MemoryTracker* tracker) const { tracker->TrackField("stats_field_array", stats_field_array_); } -FSReqBase* GetReqWrap(Environment* env, v8::Local value, +FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo& args, + int index, bool use_bigint) { + v8::Local value = args[index]; if (value->IsObject()) { return Unwrap(value.As()); - } else if (value->StrictEquals(env->fs_use_promises_symbol())) { + } + + BindingData* binding_data = Unwrap(args.Data()); + Environment* env = binding_data->env(); + if (value->StrictEquals(env->fs_use_promises_symbol())) { if (use_bigint) { - return FSReqPromise::New(env, use_bigint); + return FSReqPromise::New(binding_data, use_bigint); } else { - return FSReqPromise::New(env, use_bigint); + return FSReqPromise::New(binding_data, use_bigint); } } return nullptr; diff --git a/src/node_file.cc b/src/node_file.cc index d00595d1ca94ab..ea0f465fe8de54 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -120,30 +120,35 @@ void FSReqBase::MemoryInfo(MemoryTracker* tracker) const { // The FileHandle object wraps a file descriptor and will close it on garbage // collection if necessary. If that happens, a process warning will be // emitted (or a fatal exception will occur if the fd cannot be closed.) -FileHandle::FileHandle(Environment* env, Local obj, int fd) - : AsyncWrap(env, obj, AsyncWrap::PROVIDER_FILEHANDLE), - StreamBase(env), - fd_(fd) { +FileHandle::FileHandle(BindingData* binding_data, + Local obj, int fd) + : AsyncWrap(binding_data->env(), obj, AsyncWrap::PROVIDER_FILEHANDLE), + StreamBase(env()), + fd_(fd), + binding_data_(binding_data) { MakeWeak(); StreamBase::AttachToObject(GetObject()); } -FileHandle* FileHandle::New(Environment* env, int fd, Local obj) { +FileHandle* FileHandle::New(BindingData* binding_data, + int fd, Local obj) { + Environment* env = binding_data->env(); if (obj.IsEmpty() && !env->fd_constructor_template() ->NewInstance(env->context()) .ToLocal(&obj)) { return nullptr; } - return new FileHandle(env, obj, fd); + return new FileHandle(binding_data, obj, fd); } void FileHandle::New(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + BindingData* binding_data = Unwrap(args.Data()); + Environment* env = binding_data->env(); CHECK(args.IsConstructCall()); CHECK(args[0]->IsInt32()); FileHandle* handle = - FileHandle::New(env, args[0].As()->Value(), args.This()); + FileHandle::New(binding_data, args[0].As()->Value(), args.This()); if (handle == nullptr) return; if (args[1]->IsNumber()) handle->read_offset_ = args[1]->IntegerValue(env->context()).FromJust(); @@ -362,7 +367,7 @@ int FileHandle::ReadStart() { if (current_read_) return 0; - std::unique_ptr read_wrap; + BaseObjectPtr read_wrap; if (read_length_ == 0) { EmitRead(UV_EOF); @@ -376,7 +381,7 @@ int FileHandle::ReadStart() { HandleScope handle_scope(env()->isolate()); AsyncHooks::DefaultTriggerAsyncIdScope trigger_scope(this); - auto& freelist = env()->file_handle_read_wrap_freelist(); + auto& freelist = binding_data_->file_handle_read_wrap_freelist; if (freelist.size() > 0) { read_wrap = std::move(freelist.back()); freelist.pop_back(); @@ -395,7 +400,7 @@ int FileHandle::ReadStart() { .ToLocal(&wrap_obj)) { return UV_EBUSY; } - read_wrap = std::make_unique(this, wrap_obj); + read_wrap = MakeDetachedBaseObject(this, wrap_obj); } } int64_t recommended_read = 65536; @@ -422,7 +427,7 @@ int FileHandle::ReadStart() { // ReadStart() checks whether current_read_ is set to determine whether // a read is in progress. Moving it into a local variable makes sure that // the ReadStart() call below doesn't think we're still actively reading. - std::unique_ptr read_wrap = + BaseObjectPtr read_wrap = std::move(handle->current_read_); int result = req->result; @@ -433,7 +438,7 @@ int FileHandle::ReadStart() { // Push the read wrap back to the freelist, or let it be destroyed // once we’re exiting the current scope. constexpr size_t wanted_freelist_fill = 100; - auto& freelist = handle->env()->file_handle_read_wrap_freelist(); + auto& freelist = handle->binding_data_->file_handle_read_wrap_freelist; if (freelist.size() < wanted_freelist_fill) { read_wrap->Reset(); freelist.emplace_back(std::move(read_wrap)); @@ -503,7 +508,7 @@ void FSReqCallback::Reject(Local reject) { } void FSReqCallback::ResolveStat(const uv_stat_t* stat) { - Resolve(FillGlobalStatsArray(env(), use_bigint(), stat)); + Resolve(FillGlobalStatsArray(binding_data(), use_bigint(), stat)); } void FSReqCallback::Resolve(Local value) { @@ -522,8 +527,8 @@ void FSReqCallback::SetReturnValue(const FunctionCallbackInfo& args) { void NewFSReqCallback(const FunctionCallbackInfo& args) { CHECK(args.IsConstructCall()); - Environment* env = Environment::GetCurrent(args); - new FSReqCallback(env, args.This(), args[0]->IsTrue()); + BindingData* binding_data = Unwrap(args.Data()); + new FSReqCallback(binding_data, args.This(), args[0]->IsTrue()); } FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req) @@ -595,7 +600,7 @@ void AfterOpenFileHandle(uv_fs_t* req) { FSReqAfterScope after(req_wrap, req); if (after.Proceed()) { - FileHandle* fd = FileHandle::New(req_wrap->env(), req->result); + FileHandle* fd = FileHandle::New(req_wrap->binding_data(), req->result); if (fd == nullptr) return; req_wrap->Resolve(fd->object()); } @@ -773,7 +778,7 @@ void Access(const FunctionCallbackInfo& args) { BufferValue path(isolate, args[0]); CHECK_NOT_NULL(*path); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { // access(path, mode, req) AsyncCall(env, req_wrap_async, args, "access", UTF8, AfterNoArgs, uv_fs_access, *path, mode); @@ -796,7 +801,7 @@ void Close(const FunctionCallbackInfo& args) { CHECK(args[0]->IsInt32()); int fd = args[0].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[1]); + FSReqBase* req_wrap_async = GetReqWrap(args, 1); if (req_wrap_async != nullptr) { // close(fd, req) AsyncCall(env, req_wrap_async, args, "close", UTF8, AfterNoArgs, uv_fs_close, fd); @@ -929,7 +934,8 @@ static void InternalModuleStat(const FunctionCallbackInfo& args) { } static void Stat(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + BindingData* binding_data = Unwrap(args.Data()); + Environment* env = binding_data->env(); const int argc = args.Length(); CHECK_GE(argc, 2); @@ -938,7 +944,7 @@ static void Stat(const FunctionCallbackInfo& args) { CHECK_NOT_NULL(*path); bool use_bigint = args[1]->IsTrue(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint); + FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint); if (req_wrap_async != nullptr) { // stat(path, use_bigint, req) AsyncCall(env, req_wrap_async, args, "stat", UTF8, AfterStat, uv_fs_stat, *path); @@ -952,14 +958,15 @@ static void Stat(const FunctionCallbackInfo& args) { return; // error info is in ctx } - Local arr = FillGlobalStatsArray(env, use_bigint, + Local arr = FillGlobalStatsArray(binding_data, use_bigint, static_cast(req_wrap_sync.req.ptr)); args.GetReturnValue().Set(arr); } } static void LStat(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + BindingData* binding_data = Unwrap(args.Data()); + Environment* env = binding_data->env(); const int argc = args.Length(); CHECK_GE(argc, 3); @@ -968,7 +975,7 @@ static void LStat(const FunctionCallbackInfo& args) { CHECK_NOT_NULL(*path); bool use_bigint = args[1]->IsTrue(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint); + FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint); if (req_wrap_async != nullptr) { // lstat(path, use_bigint, req) AsyncCall(env, req_wrap_async, args, "lstat", UTF8, AfterStat, uv_fs_lstat, *path); @@ -983,14 +990,15 @@ static void LStat(const FunctionCallbackInfo& args) { return; // error info is in ctx } - Local arr = FillGlobalStatsArray(env, use_bigint, + Local arr = FillGlobalStatsArray(binding_data, use_bigint, static_cast(req_wrap_sync.req.ptr)); args.GetReturnValue().Set(arr); } } static void FStat(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + BindingData* binding_data = Unwrap(args.Data()); + Environment* env = binding_data->env(); const int argc = args.Length(); CHECK_GE(argc, 2); @@ -999,7 +1007,7 @@ static void FStat(const FunctionCallbackInfo& args) { int fd = args[0].As()->Value(); bool use_bigint = args[1]->IsTrue(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2], use_bigint); + FSReqBase* req_wrap_async = GetReqWrap(args, 2, use_bigint); if (req_wrap_async != nullptr) { // fstat(fd, use_bigint, req) AsyncCall(env, req_wrap_async, args, "fstat", UTF8, AfterStat, uv_fs_fstat, fd); @@ -1013,7 +1021,7 @@ static void FStat(const FunctionCallbackInfo& args) { return; // error info is in ctx } - Local arr = FillGlobalStatsArray(env, use_bigint, + Local arr = FillGlobalStatsArray(binding_data, use_bigint, static_cast(req_wrap_sync.req.ptr)); args.GetReturnValue().Set(arr); } @@ -1034,7 +1042,7 @@ static void Symlink(const FunctionCallbackInfo& args) { CHECK(args[2]->IsInt32()); int flags = args[2].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // symlink(target, path, flags, req) AsyncDestCall(env, req_wrap_async, args, "symlink", *path, path.length(), UTF8, AfterNoArgs, uv_fs_symlink, *target, *path, flags); @@ -1061,7 +1069,7 @@ static void Link(const FunctionCallbackInfo& args) { BufferValue dest(isolate, args[1]); CHECK_NOT_NULL(*dest); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { // link(src, dest, req) AsyncDestCall(env, req_wrap_async, args, "link", *dest, dest.length(), UTF8, AfterNoArgs, uv_fs_link, *src, *dest); @@ -1087,7 +1095,7 @@ static void ReadLink(const FunctionCallbackInfo& args) { const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { // readlink(path, encoding, req) AsyncCall(env, req_wrap_async, args, "readlink", encoding, AfterStringPtr, uv_fs_readlink, *path); @@ -1130,7 +1138,7 @@ static void Rename(const FunctionCallbackInfo& args) { BufferValue new_path(isolate, args[1]); CHECK_NOT_NULL(*new_path); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { AsyncDestCall(env, req_wrap_async, args, "rename", *new_path, new_path.length(), UTF8, AfterNoArgs, uv_fs_rename, @@ -1157,7 +1165,7 @@ static void FTruncate(const FunctionCallbackInfo& args) { CHECK(IsSafeJsInt(args[1])); const int64_t len = args[1].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { AsyncCall(env, req_wrap_async, args, "ftruncate", UTF8, AfterNoArgs, uv_fs_ftruncate, fd, len); @@ -1180,7 +1188,7 @@ static void Fdatasync(const FunctionCallbackInfo& args) { CHECK(args[0]->IsInt32()); const int fd = args[0].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[1]); + FSReqBase* req_wrap_async = GetReqWrap(args, 1); if (req_wrap_async != nullptr) { AsyncCall(env, req_wrap_async, args, "fdatasync", UTF8, AfterNoArgs, uv_fs_fdatasync, fd); @@ -1202,7 +1210,7 @@ static void Fsync(const FunctionCallbackInfo& args) { CHECK(args[0]->IsInt32()); const int fd = args[0].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[1]); + FSReqBase* req_wrap_async = GetReqWrap(args, 1); if (req_wrap_async != nullptr) { AsyncCall(env, req_wrap_async, args, "fsync", UTF8, AfterNoArgs, uv_fs_fsync, fd); @@ -1224,7 +1232,7 @@ static void Unlink(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); - FSReqBase* req_wrap_async = GetReqWrap(env, args[1]); + FSReqBase* req_wrap_async = GetReqWrap(args, 1); if (req_wrap_async != nullptr) { AsyncCall(env, req_wrap_async, args, "unlink", UTF8, AfterNoArgs, uv_fs_unlink, *path); @@ -1246,7 +1254,7 @@ static void RMDir(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); - FSReqBase* req_wrap_async = GetReqWrap(env, args[1]); // rmdir(path, req) + FSReqBase* req_wrap_async = GetReqWrap(args, 1); // rmdir(path, req) if (req_wrap_async != nullptr) { AsyncCall(env, req_wrap_async, args, "rmdir", UTF8, AfterNoArgs, uv_fs_rmdir, *path); @@ -1456,7 +1464,7 @@ static void MKDir(const FunctionCallbackInfo& args) { CHECK(args[2]->IsBoolean()); bool mkdirp = args[2]->IsTrue(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // mkdir(path, mode, req) AsyncCall(env, req_wrap_async, args, "mkdir", UTF8, mkdirp ? AfterMkdirp : AfterNoArgs, @@ -1502,7 +1510,7 @@ static void RealPath(const FunctionCallbackInfo& args) { const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { // realpath(path, encoding, req) AsyncCall(env, req_wrap_async, args, "realpath", encoding, AfterStringPtr, uv_fs_realpath, *path); @@ -1548,7 +1556,7 @@ static void ReadDir(const FunctionCallbackInfo& args) { bool with_types = args[2]->IsTrue(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // readdir(path, encoding, withTypes, req) if (with_types) { AsyncCall(env, req_wrap_async, args, "scandir", encoding, @@ -1636,7 +1644,7 @@ static void Open(const FunctionCallbackInfo& args) { CHECK(args[2]->IsInt32()); const int mode = args[2].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // open(path, flags, mode, req) AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterInteger, uv_fs_open, *path, flags, mode); @@ -1652,7 +1660,8 @@ static void Open(const FunctionCallbackInfo& args) { } static void OpenFileHandle(const FunctionCallbackInfo& args) { - Environment* env = Environment::GetCurrent(args); + BindingData* binding_data = Unwrap(args.Data()); + Environment* env = binding_data->env(); Isolate* isolate = env->isolate(); const int argc = args.Length(); @@ -1667,7 +1676,7 @@ static void OpenFileHandle(const FunctionCallbackInfo& args) { CHECK(args[2]->IsInt32()); const int mode = args[2].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // openFileHandle(path, flags, mode, req) AsyncCall(env, req_wrap_async, args, "open", UTF8, AfterOpenFileHandle, uv_fs_open, *path, flags, mode); @@ -1681,7 +1690,7 @@ static void OpenFileHandle(const FunctionCallbackInfo& args) { if (result < 0) { return; // syscall failed, no need to continue, error info is in ctx } - FileHandle* fd = FileHandle::New(env, result); + FileHandle* fd = FileHandle::New(binding_data, result); if (fd == nullptr) return; args.GetReturnValue().Set(fd->object()); } @@ -1703,7 +1712,7 @@ static void CopyFile(const FunctionCallbackInfo& args) { CHECK(args[2]->IsInt32()); const int flags = args[2].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // copyFile(src, dest, flags, req) AsyncDestCall(env, req_wrap_async, args, "copyfile", *dest, dest.length(), UTF8, AfterNoArgs, @@ -1759,7 +1768,7 @@ static void WriteBuffer(const FunctionCallbackInfo& args) { char* buf = buffer_data + off; uv_buf_t uvbuf = uv_buf_init(buf, len); - FSReqBase* req_wrap_async = GetReqWrap(env, args[5]); + FSReqBase* req_wrap_async = GetReqWrap(args, 5); if (req_wrap_async != nullptr) { // write(fd, buffer, off, len, pos, req) AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger, uv_fs_write, fd, &uvbuf, 1, pos); @@ -1804,7 +1813,7 @@ static void WriteBuffers(const FunctionCallbackInfo& args) { iovs[i] = uv_buf_init(Buffer::Data(chunk), Buffer::Length(chunk)); } - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // writeBuffers(fd, chunks, pos, req) AsyncCall(env, req_wrap_async, args, "write", UTF8, AfterInteger, uv_fs_write, fd, *iovs, iovs.length(), pos); @@ -1846,7 +1855,7 @@ static void WriteString(const FunctionCallbackInfo& args) { char* buf = nullptr; size_t len; - FSReqBase* req_wrap_async = GetReqWrap(env, args[4]); + FSReqBase* req_wrap_async = GetReqWrap(args, 4); const bool is_async = req_wrap_async != nullptr; // Avoid copying the string when it is externalized but only when: @@ -1960,7 +1969,7 @@ static void Read(const FunctionCallbackInfo& args) { char* buf = buffer_data + off; uv_buf_t uvbuf = uv_buf_init(buf, len); - FSReqBase* req_wrap_async = GetReqWrap(env, args[5]); + FSReqBase* req_wrap_async = GetReqWrap(args, 5); if (req_wrap_async != nullptr) { // read(fd, buffer, offset, len, pos, req) AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger, uv_fs_read, fd, &uvbuf, 1, pos); @@ -2006,7 +2015,7 @@ static void ReadBuffers(const FunctionCallbackInfo& args) { iovs[i] = uv_buf_init(Buffer::Data(buffer), Buffer::Length(buffer)); } - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // readBuffers(fd, buffers, pos, req) AsyncCall(env, req_wrap_async, args, "read", UTF8, AfterInteger, uv_fs_read, fd, *iovs, iovs.length(), pos); @@ -2037,7 +2046,7 @@ static void Chmod(const FunctionCallbackInfo& args) { CHECK(args[1]->IsInt32()); int mode = args[1].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { // chmod(path, mode, req) AsyncCall(env, req_wrap_async, args, "chmod", UTF8, AfterNoArgs, uv_fs_chmod, *path, mode); @@ -2067,7 +2076,7 @@ static void FChmod(const FunctionCallbackInfo& args) { CHECK(args[1]->IsInt32()); const int mode = args[1].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { // fchmod(fd, mode, req) AsyncCall(env, req_wrap_async, args, "fchmod", UTF8, AfterNoArgs, uv_fs_fchmod, fd, mode); @@ -2100,7 +2109,7 @@ static void Chown(const FunctionCallbackInfo& args) { CHECK(args[2]->IsUint32()); const uv_gid_t gid = static_cast(args[2].As()->Value()); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // chown(path, uid, gid, req) AsyncCall(env, req_wrap_async, args, "chown", UTF8, AfterNoArgs, uv_fs_chown, *path, uid, gid); @@ -2133,7 +2142,7 @@ static void FChown(const FunctionCallbackInfo& args) { CHECK(args[2]->IsUint32()); const uv_gid_t gid = static_cast(args[2].As()->Value()); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // fchown(fd, uid, gid, req) AsyncCall(env, req_wrap_async, args, "fchown", UTF8, AfterNoArgs, uv_fs_fchown, fd, uid, gid); @@ -2163,7 +2172,7 @@ static void LChown(const FunctionCallbackInfo& args) { CHECK(args[2]->IsUint32()); const uv_gid_t gid = static_cast(args[2].As()->Value()); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // lchown(path, uid, gid, req) AsyncCall(env, req_wrap_async, args, "lchown", UTF8, AfterNoArgs, uv_fs_lchown, *path, uid, gid); @@ -2193,7 +2202,7 @@ static void UTimes(const FunctionCallbackInfo& args) { CHECK(args[2]->IsNumber()); const double mtime = args[2].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // utimes(path, atime, mtime, req) AsyncCall(env, req_wrap_async, args, "utime", UTF8, AfterNoArgs, uv_fs_utime, *path, atime, mtime); @@ -2222,7 +2231,7 @@ static void FUTimes(const FunctionCallbackInfo& args) { CHECK(args[2]->IsNumber()); const double mtime = args[2].As()->Value(); - FSReqBase* req_wrap_async = GetReqWrap(env, args[3]); + FSReqBase* req_wrap_async = GetReqWrap(args, 3); if (req_wrap_async != nullptr) { // futimes(fd, atime, mtime, req) AsyncCall(env, req_wrap_async, args, "futime", UTF8, AfterNoArgs, uv_fs_futime, fd, atime, mtime); @@ -2248,7 +2257,7 @@ static void Mkdtemp(const FunctionCallbackInfo& args) { const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8); - FSReqBase* req_wrap_async = GetReqWrap(env, args[2]); + FSReqBase* req_wrap_async = GetReqWrap(args, 2); if (req_wrap_async != nullptr) { // mkdtemp(tmpl, encoding, req) AsyncCall(env, req_wrap_async, args, "mkdtemp", encoding, AfterStringPath, uv_fs_mkdtemp, *tmpl); @@ -2273,12 +2282,22 @@ static void Mkdtemp(const FunctionCallbackInfo& args) { } } +void BindingData::MemoryInfo(MemoryTracker* tracker) const { + tracker->TrackField("stats_field_array", stats_field_array); + tracker->TrackField("stats_field_bigint_array", stats_field_bigint_array); + tracker->TrackField("file_handle_read_wrap_freelist", + file_handle_read_wrap_freelist); +} + void Initialize(Local target, Local unused, Local context, void* priv) { Environment* env = Environment::GetCurrent(context); Isolate* isolate = env->isolate(); + Environment::BindingScope binding_scope(env); + if (!binding_scope) return; + BindingData* binding_data = binding_scope.data; env->SetMethod(target, "access", Access); env->SetMethod(target, "close", Close); @@ -2331,11 +2350,11 @@ void Initialize(Local target, target->Set(context, FIXED_ONE_BYTE_STRING(isolate, "statValues"), - env->fs_stats_field_array()->GetJSArray()).Check(); + binding_data->stats_field_array.GetJSArray()).Check(); target->Set(context, FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"), - env->fs_stats_field_bigint_array()->GetJSArray()).Check(); + binding_data->stats_field_bigint_array.GetJSArray()).Check(); StatWatcher::Initialize(env, target); diff --git a/src/node_file.h b/src/node_file.h index 1ebfe06c1fbdbf..1fda81361fef79 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -11,6 +11,26 @@ namespace node { namespace fs { +class FileHandleReadWrap; + +class BindingData : public BaseObject { + public: + explicit BindingData(Environment* env, v8::Local wrap) + : BaseObject(env, wrap), + stats_field_array(env->isolate(), kFsStatsBufferLength), + stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) {} + + AliasedFloat64Array stats_field_array; + AliasedBigUint64Array stats_field_bigint_array; + + std::vector> + file_handle_read_wrap_freelist; + + void MemoryInfo(MemoryTracker* tracker) const override; + SET_SELF_SIZE(BindingData) + SET_MEMORY_INFO_NAME(BindingData) +}; + // structure used to store state during a complex operation, e.g., mkdirp. class FSContinuationData : public MemoryRetainer { public: @@ -43,7 +63,7 @@ class FSReqBase : public ReqWrap { public: typedef MaybeStackBuffer FSReqBuffer; - inline FSReqBase(Environment* env, + inline FSReqBase(BindingData* binding_data, v8::Local req, AsyncWrap::ProviderType type, bool use_bigint); @@ -83,12 +103,16 @@ class FSReqBase : public ReqWrap { void MemoryInfo(MemoryTracker* tracker) const override; + BindingData* binding_data() { return binding_data_.get(); } + private: std::unique_ptr continuation_data_; enum encoding encoding_ = UTF8; bool has_data_ = false; - const char* syscall_ = nullptr; bool use_bigint_ = false; + const char* syscall_ = nullptr; + + BaseObjectPtr binding_data_; // Typically, the content of buffer_ is something like a file name, so // something around 64 bytes should be enough. @@ -97,7 +121,7 @@ class FSReqBase : public ReqWrap { class FSReqCallback final : public FSReqBase { public: - inline FSReqCallback(Environment* env, + inline FSReqCallback(BindingData* binding_data, v8::Local req, bool use_bigint); @@ -118,7 +142,7 @@ void FillStatsArray(AliasedBufferBase* fields, const uv_stat_t* s, const size_t offset = 0); -inline v8::Local FillGlobalStatsArray(Environment* env, +inline v8::Local FillGlobalStatsArray(BindingData* binding_data, const bool use_bigint, const uv_stat_t* s, const bool second = false); @@ -126,7 +150,8 @@ inline v8::Local FillGlobalStatsArray(Environment* env, template class FSReqPromise final : public FSReqBase { public: - static inline FSReqPromise* New(Environment* env, bool use_bigint); + static inline FSReqPromise* New(BindingData* binding_data, + bool use_bigint); inline ~FSReqPromise() override; inline void Reject(v8::Local reject) override; @@ -145,7 +170,7 @@ class FSReqPromise final : public FSReqBase { FSReqPromise& operator=(const FSReqPromise&&) = delete; private: - inline FSReqPromise(Environment* env, + inline FSReqPromise(BindingData* binding_data, v8::Local obj, bool use_bigint); @@ -202,7 +227,7 @@ class FileHandleReadWrap final : public ReqWrap { // the object is garbage collected class FileHandle final : public AsyncWrap, public StreamBase { public: - static FileHandle* New(Environment* env, + static FileHandle* New(BindingData* binding_data, int fd, v8::Local obj = v8::Local()); ~FileHandle() override; @@ -246,7 +271,7 @@ class FileHandle final : public AsyncWrap, public StreamBase { FileHandle& operator=(const FileHandle&&) = delete; private: - FileHandle(Environment* env, v8::Local obj, int fd); + FileHandle(BindingData* binding_data, v8::Local obj, int fd); // Synchronous close that emits a warning void Close(); @@ -295,7 +320,9 @@ class FileHandle final : public AsyncWrap, public StreamBase { int64_t read_length_ = -1; bool reading_ = false; - std::unique_ptr current_read_ = nullptr; + BaseObjectPtr current_read_; + + BaseObjectPtr binding_data_; }; int MKDirpSync(uv_loop_t* loop, @@ -327,7 +354,8 @@ class FSReqWrapSync { // TODO(addaleax): Currently, callers check the return value and assume // that nullptr indicates a synchronous call, rather than a failure. // Failure conditions should be disambiguated and handled appropriately. -inline FSReqBase* GetReqWrap(Environment* env, v8::Local value, +inline FSReqBase* GetReqWrap(const v8::FunctionCallbackInfo& args, + int index, bool use_bigint = false); // Returns nullptr if the operation fails from the start. diff --git a/src/node_stat_watcher.cc b/src/node_stat_watcher.cc index 05c540bbff17cc..af23affc412935 100644 --- a/src/node_stat_watcher.cc +++ b/src/node_stat_watcher.cc @@ -61,15 +61,16 @@ void StatWatcher::Initialize(Environment* env, Local target) { } -StatWatcher::StatWatcher(Environment* env, +StatWatcher::StatWatcher(fs::BindingData* binding_data, Local wrap, bool use_bigint) - : HandleWrap(env, + : HandleWrap(binding_data->env(), wrap, reinterpret_cast(&watcher_), AsyncWrap::PROVIDER_STATWATCHER), - use_bigint_(use_bigint) { - CHECK_EQ(0, uv_fs_poll_init(env->event_loop(), &watcher_)); + use_bigint_(use_bigint), + binding_data_(binding_data) { + CHECK_EQ(0, uv_fs_poll_init(env()->event_loop(), &watcher_)); } @@ -82,8 +83,10 @@ void StatWatcher::Callback(uv_fs_poll_t* handle, HandleScope handle_scope(env->isolate()); Context::Scope context_scope(env->context()); - Local arr = fs::FillGlobalStatsArray(env, wrap->use_bigint_, curr); - USE(fs::FillGlobalStatsArray(env, wrap->use_bigint_, prev, true)); + Local arr = fs::FillGlobalStatsArray( + wrap->binding_data_.get(), wrap->use_bigint_, curr); + USE(fs::FillGlobalStatsArray( + wrap->binding_data_.get(), wrap->use_bigint_, prev, true)); Local argv[2] = { Integer::New(env->isolate(), status), arr }; wrap->MakeCallback(env->onchange_string(), arraysize(argv), argv); @@ -92,8 +95,8 @@ void StatWatcher::Callback(uv_fs_poll_t* handle, void StatWatcher::New(const FunctionCallbackInfo& args) { CHECK(args.IsConstructCall()); - Environment* env = Environment::GetCurrent(args); - new StatWatcher(env, args.This(), args[0]->IsTrue()); + fs::BindingData* binding_data = Unwrap(args.Data()); + new StatWatcher(binding_data, args.This(), args[0]->IsTrue()); } // wrap.start(filename, interval) diff --git a/src/node_stat_watcher.h b/src/node_stat_watcher.h index 9669806ce796c9..81a8903018624b 100644 --- a/src/node_stat_watcher.h +++ b/src/node_stat_watcher.h @@ -30,6 +30,9 @@ #include "v8.h" namespace node { +namespace fs { +struct BindingData; +} class Environment; @@ -38,7 +41,7 @@ class StatWatcher : public HandleWrap { static void Initialize(Environment* env, v8::Local target); protected: - StatWatcher(Environment* env, + StatWatcher(fs::BindingData* binding_data, v8::Local wrap, bool use_bigint); @@ -57,6 +60,7 @@ class StatWatcher : public HandleWrap { uv_fs_poll_t watcher_; const bool use_bigint_; + BaseObjectPtr binding_data_; }; } // namespace node