src: refactor FillStatsArray
PR-URL: https://github.com/nodejs/node/pull/23793 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
This commit is contained in:
parent
6786ff4d36
commit
fb897fbae0
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
const errors = require('internal/errors');
|
const errors = require('internal/errors');
|
||||||
const {
|
const {
|
||||||
kFsStatsFieldsLength,
|
kFsStatsFieldsNumber,
|
||||||
StatWatcher: _StatWatcher
|
StatWatcher: _StatWatcher
|
||||||
} = process.binding('fs');
|
} = process.binding('fs');
|
||||||
const { FSEvent } = internalBinding('fs_event_wrap');
|
const { FSEvent } = internalBinding('fs_event_wrap');
|
||||||
@ -48,7 +48,7 @@ function onchange(newStatus, stats) {
|
|||||||
|
|
||||||
self[kOldStatus] = newStatus;
|
self[kOldStatus] = newStatus;
|
||||||
self.emit('change', getStatsFromBinding(stats),
|
self.emit('change', getStatsFromBinding(stats),
|
||||||
getStatsFromBinding(stats, kFsStatsFieldsLength));
|
getStatsFromBinding(stats, kFsStatsFieldsNumber));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(joyeecheung): this method is not documented.
|
// FIXME(joyeecheung): this method is not documented.
|
||||||
|
@ -169,8 +169,8 @@ Environment::Environment(IsolateData* isolate_data,
|
|||||||
trace_category_state_(isolate_, kTraceCategoryCount),
|
trace_category_state_(isolate_, kTraceCategoryCount),
|
||||||
stream_base_state_(isolate_, StreamBase::kNumStreamBaseStateFields),
|
stream_base_state_(isolate_, StreamBase::kNumStreamBaseStateFields),
|
||||||
http_parser_buffer_(nullptr),
|
http_parser_buffer_(nullptr),
|
||||||
fs_stats_field_array_(isolate_, kFsStatsFieldsLength * 2),
|
fs_stats_field_array_(isolate_, kFsStatsBufferLength),
|
||||||
fs_stats_field_bigint_array_(isolate_, kFsStatsFieldsLength * 2),
|
fs_stats_field_bigint_array_(isolate_, kFsStatsBufferLength),
|
||||||
context_(context->GetIsolate(), context) {
|
context_(context->GetIsolate(), context) {
|
||||||
// We'll be creating new objects so make sure we've entered the context.
|
// We'll be creating new objects so make sure we've entered the context.
|
||||||
v8::HandleScope handle_scope(isolate());
|
v8::HandleScope handle_scope(isolate());
|
||||||
|
13
src/env.h
13
src/env.h
@ -84,9 +84,12 @@ struct PackageConfig {
|
|||||||
|
|
||||||
// The number of items passed to push_values_to_array_function has diminishing
|
// The number of items passed to push_values_to_array_function has diminishing
|
||||||
// returns around 8. This should be used at all call sites using said function.
|
// returns around 8. This should be used at all call sites using said function.
|
||||||
#ifndef NODE_PUSH_VAL_TO_ARRAY_MAX
|
constexpr size_t NODE_PUSH_VAL_TO_ARRAY_MAX = 8;
|
||||||
#define NODE_PUSH_VAL_TO_ARRAY_MAX 8
|
|
||||||
#endif
|
// Stat fields buffers contain twice the number of entries in an uv_stat_t
|
||||||
|
// because `fs.StatWatcher` needs room to store 2 `fs.Stats` instances.
|
||||||
|
constexpr size_t kFsStatsFieldsNumber = 14;
|
||||||
|
constexpr size_t kFsStatsBufferLength = kFsStatsFieldsNumber * 2;
|
||||||
|
|
||||||
// PER_ISOLATE_* macros: We have a lot of per-isolate properties
|
// PER_ISOLATE_* macros: We have a lot of per-isolate properties
|
||||||
// and adding and maintaining their getters and setters by hand would be
|
// and adding and maintaining their getters and setters by hand would be
|
||||||
@ -710,10 +713,6 @@ class Environment {
|
|||||||
inline AliasedBuffer<uint64_t, v8::BigUint64Array>*
|
inline AliasedBuffer<uint64_t, v8::BigUint64Array>*
|
||||||
fs_stats_field_bigint_array();
|
fs_stats_field_bigint_array();
|
||||||
|
|
||||||
// stat fields contains twice the number of entries because `fs.StatWatcher`
|
|
||||||
// needs room to store data for *two* `fs.Stats` instances.
|
|
||||||
static const int kFsStatsFieldsLength = 14;
|
|
||||||
|
|
||||||
inline std::vector<std::unique_ptr<fs::FileHandleReadWrap>>&
|
inline std::vector<std::unique_ptr<fs::FileHandleReadWrap>>&
|
||||||
file_handle_read_wrap_freelist();
|
file_handle_read_wrap_freelist();
|
||||||
|
|
||||||
|
@ -426,7 +426,7 @@ void FSReqCallback::Reject(Local<Value> reject) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
|
void FSReqCallback::ResolveStat(const uv_stat_t* stat) {
|
||||||
Resolve(node::FillGlobalStatsArray(env(), stat, use_bigint()));
|
Resolve(FillGlobalStatsArray(env(), use_bigint(), stat));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FSReqCallback::Resolve(Local<Value> value) {
|
void FSReqCallback::Resolve(Local<Value> value) {
|
||||||
@ -949,8 +949,8 @@ static void Stat(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return; // error info is in ctx
|
return; // error info is in ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Value> arr = node::FillGlobalStatsArray(env,
|
Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
|
||||||
static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr), use_bigint);
|
static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
|
||||||
args.GetReturnValue().Set(arr);
|
args.GetReturnValue().Set(arr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -980,8 +980,8 @@ static void LStat(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return; // error info is in ctx
|
return; // error info is in ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Value> arr = node::FillGlobalStatsArray(env,
|
Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
|
||||||
static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr), use_bigint);
|
static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
|
||||||
args.GetReturnValue().Set(arr);
|
args.GetReturnValue().Set(arr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1010,8 +1010,8 @@ static void FStat(const FunctionCallbackInfo<Value>& args) {
|
|||||||
return; // error info is in ctx
|
return; // error info is in ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
Local<Value> arr = node::FillGlobalStatsArray(env,
|
Local<Value> arr = FillGlobalStatsArray(env, use_bigint,
|
||||||
static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr), use_bigint);
|
static_cast<const uv_stat_t*>(req_wrap_sync.req.ptr));
|
||||||
args.GetReturnValue().Set(arr);
|
args.GetReturnValue().Set(arr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2237,8 +2237,8 @@ void Initialize(Local<Object> target,
|
|||||||
env->SetMethod(target, "mkdtemp", Mkdtemp);
|
env->SetMethod(target, "mkdtemp", Mkdtemp);
|
||||||
|
|
||||||
target->Set(context,
|
target->Set(context,
|
||||||
FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsLength"),
|
FIXED_ONE_BYTE_STRING(isolate, "kFsStatsFieldsNumber"),
|
||||||
Integer::New(isolate, env->kFsStatsFieldsLength))
|
Integer::New(isolate, kFsStatsFieldsNumber))
|
||||||
.FromJust();
|
.FromJust();
|
||||||
|
|
||||||
target->Set(context,
|
target->Set(context,
|
||||||
|
@ -148,6 +148,92 @@ class FSReqCallback : public FSReqBase {
|
|||||||
DISALLOW_COPY_AND_ASSIGN(FSReqCallback);
|
DISALLOW_COPY_AND_ASSIGN(FSReqCallback);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Wordaround a GCC4.9 bug that C++14 N3652 was not implemented
|
||||||
|
// Refs: https://www.gnu.org/software/gcc/projects/cxx-status.html#cxx14
|
||||||
|
// Refs: https://isocpp.org/files/papers/N3652.html
|
||||||
|
#if __cpp_constexpr < 201304
|
||||||
|
# define constexpr inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename NativeT,
|
||||||
|
// SFINAE limit NativeT to arithmetic types
|
||||||
|
typename = std::enable_if<std::is_arithmetic<NativeT>::value>>
|
||||||
|
constexpr NativeT ToNative(uv_timespec_t ts) {
|
||||||
|
// This template has exactly two specializations below.
|
||||||
|
static_assert(std::is_arithmetic<NativeT>::value == false, "Not implemented");
|
||||||
|
UNREACHABLE();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr double ToNative(uv_timespec_t ts) {
|
||||||
|
// We need to do a static_cast since the original FS values are ulong.
|
||||||
|
/* NOLINTNEXTLINE(runtime/int) */
|
||||||
|
const auto u_sec = static_cast<unsigned long>(ts.tv_sec);
|
||||||
|
const double full_sec = u_sec * 1000.0;
|
||||||
|
/* NOLINTNEXTLINE(runtime/int) */
|
||||||
|
const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec);
|
||||||
|
const double full_nsec = u_nsec / 1000'000.0;
|
||||||
|
return full_sec + full_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
constexpr uint64_t ToNative(uv_timespec_t ts) {
|
||||||
|
// We need to do a static_cast since the original FS values are ulong.
|
||||||
|
/* NOLINTNEXTLINE(runtime/int) */
|
||||||
|
const auto u_sec = static_cast<unsigned long>(ts.tv_sec);
|
||||||
|
const auto full_sec = static_cast<uint64_t>(u_sec) * 1000UL;
|
||||||
|
/* NOLINTNEXTLINE(runtime/int) */
|
||||||
|
const auto u_nsec = static_cast<unsigned long>(ts.tv_nsec);
|
||||||
|
const auto full_nsec = static_cast<uint64_t>(u_nsec) / 1000'000UL;
|
||||||
|
return full_sec + full_nsec;
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef constexpr // end N3652 bug workaround
|
||||||
|
|
||||||
|
template <typename NativeT, typename V8T>
|
||||||
|
constexpr void FillStatsArray(AliasedBuffer<NativeT, V8T>* fields,
|
||||||
|
const uv_stat_t* s, const size_t offset = 0) {
|
||||||
|
fields->SetValue(offset + 0, s->st_dev);
|
||||||
|
fields->SetValue(offset + 1, s->st_mode);
|
||||||
|
fields->SetValue(offset + 2, s->st_nlink);
|
||||||
|
fields->SetValue(offset + 3, s->st_uid);
|
||||||
|
fields->SetValue(offset + 4, s->st_gid);
|
||||||
|
fields->SetValue(offset + 5, s->st_rdev);
|
||||||
|
#if defined(__POSIX__)
|
||||||
|
fields->SetValue(offset + 6, s->st_blksize);
|
||||||
|
#else
|
||||||
|
fields->SetValue(offset + 6, 0);
|
||||||
|
#endif
|
||||||
|
fields->SetValue(offset + 7, s->st_ino);
|
||||||
|
fields->SetValue(offset + 8, s->st_size);
|
||||||
|
#if defined(__POSIX__)
|
||||||
|
fields->SetValue(offset + 9, s->st_blocks);
|
||||||
|
#else
|
||||||
|
fields->SetValue(offset + 9, 0);
|
||||||
|
#endif
|
||||||
|
// Dates.
|
||||||
|
fields->SetValue(offset + 10, ToNative<NativeT>(s->st_atim));
|
||||||
|
fields->SetValue(offset + 11, ToNative<NativeT>(s->st_mtim));
|
||||||
|
fields->SetValue(offset + 12, ToNative<NativeT>(s->st_ctim));
|
||||||
|
fields->SetValue(offset + 13, ToNative<NativeT>(s->st_birthtim));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Local<Value> FillGlobalStatsArray(Environment* env,
|
||||||
|
const bool use_bigint,
|
||||||
|
const uv_stat_t* s,
|
||||||
|
const bool second = false) {
|
||||||
|
const ptrdiff_t offset = second ? kFsStatsFieldsNumber : 0;
|
||||||
|
if (use_bigint) {
|
||||||
|
auto* const arr = env->fs_stats_field_bigint_array();
|
||||||
|
FillStatsArray(arr, s, offset);
|
||||||
|
return arr->GetJSArray();
|
||||||
|
} else {
|
||||||
|
auto* const arr = env->fs_stats_field_array();
|
||||||
|
FillStatsArray(arr, s, offset);
|
||||||
|
return arr->GetJSArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename NativeT = double, typename V8T = v8::Float64Array>
|
template <typename NativeT = double, typename V8T = v8::Float64Array>
|
||||||
class FSReqPromise : public FSReqBase {
|
class FSReqPromise : public FSReqBase {
|
||||||
public:
|
public:
|
||||||
@ -157,7 +243,7 @@ class FSReqPromise : public FSReqBase {
|
|||||||
->NewInstance(env->context()).ToLocalChecked(),
|
->NewInstance(env->context()).ToLocalChecked(),
|
||||||
AsyncWrap::PROVIDER_FSREQPROMISE,
|
AsyncWrap::PROVIDER_FSREQPROMISE,
|
||||||
use_bigint),
|
use_bigint),
|
||||||
stats_field_array_(env->isolate(), env->kFsStatsFieldsLength) {
|
stats_field_array_(env->isolate(), kFsStatsFieldsNumber) {
|
||||||
auto resolver = Promise::Resolver::New(env->context()).ToLocalChecked();
|
auto resolver = Promise::Resolver::New(env->context()).ToLocalChecked();
|
||||||
object()->Set(env->context(), env->promise_string(),
|
object()->Set(env->context(), env->promise_string(),
|
||||||
resolver).FromJust();
|
resolver).FromJust();
|
||||||
@ -191,7 +277,8 @@ class FSReqPromise : public FSReqBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ResolveStat(const uv_stat_t* stat) override {
|
void ResolveStat(const uv_stat_t* stat) override {
|
||||||
Resolve(node::FillStatsArray(&stats_field_array_, stat));
|
FillStatsArray(&stats_field_array_, stat);
|
||||||
|
Resolve(stats_field_array_.GetJSArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetReturnValue(const FunctionCallbackInfo<Value>& args) override {
|
void SetReturnValue(const FunctionCallbackInfo<Value>& args) override {
|
||||||
|
@ -32,7 +32,6 @@
|
|||||||
#include "uv.h"
|
#include "uv.h"
|
||||||
#include "v8.h"
|
#include "v8.h"
|
||||||
#include "tracing/trace_event.h"
|
#include "tracing/trace_event.h"
|
||||||
#include "node_perf_common.h"
|
|
||||||
#include "node_api.h"
|
#include "node_api.h"
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -308,57 +307,6 @@ v8::Maybe<bool> ProcessEmitDeprecationWarning(Environment* env,
|
|||||||
const char* warning,
|
const char* warning,
|
||||||
const char* deprecation_code);
|
const char* deprecation_code);
|
||||||
|
|
||||||
template <typename NativeT, typename V8T>
|
|
||||||
v8::Local<v8::Value> FillStatsArray(AliasedBuffer<NativeT, V8T>* fields_ptr,
|
|
||||||
const uv_stat_t* s, int offset = 0) {
|
|
||||||
AliasedBuffer<NativeT, V8T>& fields = *fields_ptr;
|
|
||||||
fields[offset + 0] = s->st_dev;
|
|
||||||
fields[offset + 1] = s->st_mode;
|
|
||||||
fields[offset + 2] = s->st_nlink;
|
|
||||||
fields[offset + 3] = s->st_uid;
|
|
||||||
fields[offset + 4] = s->st_gid;
|
|
||||||
fields[offset + 5] = s->st_rdev;
|
|
||||||
#if defined(__POSIX__)
|
|
||||||
fields[offset + 6] = s->st_blksize;
|
|
||||||
#else
|
|
||||||
fields[offset + 6] = 0;
|
|
||||||
#endif
|
|
||||||
fields[offset + 7] = s->st_ino;
|
|
||||||
fields[offset + 8] = s->st_size;
|
|
||||||
#if defined(__POSIX__)
|
|
||||||
fields[offset + 9] = s->st_blocks;
|
|
||||||
#else
|
|
||||||
fields[offset + 9] = 0;
|
|
||||||
#endif
|
|
||||||
// Dates.
|
|
||||||
// NO-LINT because the fields are 'long' and we just want to cast to `unsigned`
|
|
||||||
#define X(idx, name) \
|
|
||||||
/* NOLINTNEXTLINE(runtime/int) */ \
|
|
||||||
fields[offset + idx] = ((unsigned long)(s->st_##name.tv_sec) * 1e3) + \
|
|
||||||
/* NOLINTNEXTLINE(runtime/int) */ \
|
|
||||||
((unsigned long)(s->st_##name.tv_nsec) / 1e6); \
|
|
||||||
|
|
||||||
X(10, atim)
|
|
||||||
X(11, mtim)
|
|
||||||
X(12, ctim)
|
|
||||||
X(13, birthtim)
|
|
||||||
#undef X
|
|
||||||
|
|
||||||
return fields_ptr->GetJSArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline v8::Local<v8::Value> FillGlobalStatsArray(Environment* env,
|
|
||||||
const uv_stat_t* s,
|
|
||||||
bool use_bigint = false,
|
|
||||||
int offset = 0) {
|
|
||||||
if (use_bigint) {
|
|
||||||
return node::FillStatsArray(
|
|
||||||
env->fs_stats_field_bigint_array(), s, offset);
|
|
||||||
} else {
|
|
||||||
return node::FillStatsArray(env->fs_stats_field_array(), s, offset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetupBootstrapObject(Environment* env,
|
void SetupBootstrapObject(Environment* env,
|
||||||
v8::Local<v8::Object> bootstrapper);
|
v8::Local<v8::Object> bootstrapper);
|
||||||
void SetupProcessObject(Environment* env,
|
void SetupProcessObject(Environment* env,
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
#include "node_stat_watcher.h"
|
#include "node_stat_watcher.h"
|
||||||
#include "node_internals.h"
|
#include "node_internals.h"
|
||||||
#include "async_wrap-inl.h"
|
#include "async_wrap-inl.h"
|
||||||
#include "env-inl.h"
|
#include "env.h"
|
||||||
#include "util-inl.h"
|
#include "node_file.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -80,15 +80,10 @@ void StatWatcher::Callback(uv_fs_poll_t* handle,
|
|||||||
HandleScope handle_scope(env->isolate());
|
HandleScope handle_scope(env->isolate());
|
||||||
Context::Scope context_scope(env->context());
|
Context::Scope context_scope(env->context());
|
||||||
|
|
||||||
Local<Value> arr = node::FillGlobalStatsArray(env, curr,
|
Local<Value> arr = fs::FillGlobalStatsArray(env, wrap->use_bigint_, curr);
|
||||||
wrap->use_bigint_);
|
USE(fs::FillGlobalStatsArray(env, wrap->use_bigint_, prev, true));
|
||||||
node::FillGlobalStatsArray(env, prev, wrap->use_bigint_,
|
|
||||||
env->kFsStatsFieldsLength);
|
|
||||||
|
|
||||||
Local<Value> argv[2] {
|
Local<Value> argv[2] = { Integer::New(env->isolate(), status), arr };
|
||||||
Integer::New(env->isolate(), status),
|
|
||||||
arr
|
|
||||||
};
|
|
||||||
wrap->MakeCallback(env->onchange_string(), arraysize(argv), argv);
|
wrap->MakeCallback(env->onchange_string(), arraysize(argv), argv);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user