Skip to content

Commit

Permalink
src: clean up node_file.h
Browse files Browse the repository at this point in the history
- Move inline functions into an `-inl.h` file
- Move override function definitions into `.cc` files
- Remove `using` statements from header files
- Make data fields of classes private
- Mark classes at the end of hierarchies as `final`

This is also partially being done in an attempt to avoid
a particular internal compiler error, see
#30475 (comment)
for details.

PR-URL: #30530
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: David Carlier <devnexen@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
addaleax authored and BethGriggs committed Feb 6, 2020
1 parent c79f485 commit 33064a1
Show file tree
Hide file tree
Showing 10 changed files with 462 additions and 327 deletions.
1 change: 1 addition & 0 deletions node.gyp
Expand Up @@ -616,6 +616,7 @@
'src/node_dir.h',
'src/node_errors.h',
'src/node_file.h',
'src/node_file-inl.h',
'src/node_http_parser_impl.h',
'src/node_http2.h',
'src/node_http2_state.h',
Expand Down
2 changes: 2 additions & 0 deletions src/env.cc
Expand Up @@ -11,6 +11,7 @@
#include "node_process.h"
#include "node_v8_platform-inl.h"
#include "node_worker.h"
#include "req_wrap-inl.h"
#include "tracing/agent.h"
#include "tracing/traced_value.h"
#include "util-inl.h"
Expand All @@ -35,6 +36,7 @@ using v8::HandleScope;
using v8::Integer;
using v8::Isolate;
using v8::Local;
using v8::MaybeLocal;
using v8::NewStringType;
using v8::Number;
using v8::Object;
Expand Down
7 changes: 6 additions & 1 deletion src/node_dir.cc
@@ -1,10 +1,11 @@
#include "node_dir.h"
#include "node_file-inl.h"
#include "node_process.h"
#include "memory_tracker-inl.h"
#include "util.h"

#include "tracing/trace_event.h"

#include "req_wrap-inl.h"
#include "string_bytes.h"

#include <fcntl.h>
Expand Down Expand Up @@ -85,6 +86,10 @@ DirHandle::~DirHandle() {
CHECK(closed_); // We have to be closed at the point
}

void DirHandle::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackFieldWithSize("dir", sizeof(*dir_));
}

// Close the directory handle if it hasn't already been closed. A process
// warning will be emitted using a SetImmediate to avoid calling back to
// JS during GC. If closing the fd fails at this point, a fatal exception
Expand Down
13 changes: 4 additions & 9 deletions src/node_dir.h
Expand Up @@ -4,8 +4,6 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "node_file.h"
#include "node.h"
#include "req_wrap-inl.h"

namespace node {

Expand All @@ -20,16 +18,13 @@ class DirHandle : public AsyncWrap {
~DirHandle() override;

static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Open(const v8::FunctionCallbackInfo<Value>& args);
static void Read(const v8::FunctionCallbackInfo<Value>& args);
static void Close(const v8::FunctionCallbackInfo<Value>& args);
static void Open(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Read(const v8::FunctionCallbackInfo<v8::Value>& args);
static void Close(const v8::FunctionCallbackInfo<v8::Value>& args);

inline uv_dir_t* dir() { return dir_; }

void MemoryInfo(MemoryTracker* tracker) const override {
tracker->TrackFieldWithSize("dir", sizeof(*dir_));
}

void MemoryInfo(MemoryTracker* tracker) const override;
SET_MEMORY_INFO_NAME(DirHandle)
SET_SELF_SIZE(DirHandle)

Expand Down
283 changes: 283 additions & 0 deletions src/node_file-inl.h
@@ -0,0 +1,283 @@
#ifndef SRC_NODE_FILE_INL_H_
#define SRC_NODE_FILE_INL_H_

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "node_file.h"
#include "req_wrap-inl.h"

namespace node {
namespace fs {

FSContinuationData::FSContinuationData(uv_fs_t* req, int mode, uv_fs_cb done_cb)
: done_cb_(done_cb), req_(req), mode_(mode) {
}

void FSContinuationData::PushPath(std::string&& path) {
paths_.emplace_back(std::move(path));
}

void FSContinuationData::PushPath(const std::string& path) {
paths_.push_back(path);
}

std::string FSContinuationData::PopPath() {
CHECK_GT(paths_.size(), 0);
std::string path = std::move(paths_.back());
paths_.pop_back();
return path;
}

void FSContinuationData::Done(int result) {
req_->result = result;
done_cb_(req_);
}

FSReqBase::FSReqBase(Environment* env,
v8::Local<v8::Object> req,
AsyncWrap::ProviderType type,
bool use_bigint)
: ReqWrap(env, req, type), use_bigint_(use_bigint) {
}

void FSReqBase::Init(const char* syscall,
const char* data,
size_t len,
enum encoding encoding) {
syscall_ = syscall;
encoding_ = encoding;

if (data != nullptr) {
CHECK(!has_data_);
buffer_.AllocateSufficientStorage(len + 1);
buffer_.SetLengthAndZeroTerminate(len);
memcpy(*buffer_, data, len);
has_data_ = true;
}
}

FSReqBase::FSReqBuffer&
FSReqBase::Init(const char* syscall, size_t len, enum encoding encoding) {
syscall_ = syscall;
encoding_ = encoding;

buffer_.AllocateSufficientStorage(len + 1);
has_data_ = false; // so that the data does not show up in error messages
return buffer_;
}

FSReqCallback::FSReqCallback(Environment* env,
v8::Local<v8::Object> req, bool use_bigint)
: FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQCALLBACK, use_bigint) {}

template <typename NativeT, typename V8T>
void FillStatsArray(AliasedBufferBase<NativeT, V8T>* fields,
const uv_stat_t* s,
const size_t offset) {
#define SET_FIELD_WITH_STAT(stat_offset, stat) \
fields->SetValue(offset + static_cast<size_t>(FsStatsOffset::stat_offset), \
static_cast<NativeT>(stat))

#define SET_FIELD_WITH_TIME_STAT(stat_offset, stat) \
/* NOLINTNEXTLINE(runtime/int) */ \
SET_FIELD_WITH_STAT(stat_offset, static_cast<unsigned long>(stat))

SET_FIELD_WITH_STAT(kDev, s->st_dev);
SET_FIELD_WITH_STAT(kMode, s->st_mode);
SET_FIELD_WITH_STAT(kNlink, s->st_nlink);
SET_FIELD_WITH_STAT(kUid, s->st_uid);
SET_FIELD_WITH_STAT(kGid, s->st_gid);
SET_FIELD_WITH_STAT(kRdev, s->st_rdev);
SET_FIELD_WITH_STAT(kBlkSize, s->st_blksize);
SET_FIELD_WITH_STAT(kIno, s->st_ino);
SET_FIELD_WITH_STAT(kSize, s->st_size);
SET_FIELD_WITH_STAT(kBlocks, s->st_blocks);

SET_FIELD_WITH_TIME_STAT(kATimeSec, s->st_atim.tv_sec);
SET_FIELD_WITH_TIME_STAT(kATimeNsec, s->st_atim.tv_nsec);
SET_FIELD_WITH_TIME_STAT(kMTimeSec, s->st_mtim.tv_sec);
SET_FIELD_WITH_TIME_STAT(kMTimeNsec, s->st_mtim.tv_nsec);
SET_FIELD_WITH_TIME_STAT(kCTimeSec, s->st_ctim.tv_sec);
SET_FIELD_WITH_TIME_STAT(kCTimeNsec, s->st_ctim.tv_nsec);
SET_FIELD_WITH_TIME_STAT(kBirthTimeSec, s->st_birthtim.tv_sec);
SET_FIELD_WITH_TIME_STAT(kBirthTimeNsec, s->st_birthtim.tv_nsec);

#undef SET_FIELD_WITH_TIME_STAT
#undef SET_FIELD_WITH_STAT
}

v8::Local<v8::Value> FillGlobalStatsArray(Environment* env,
const bool use_bigint,
const uv_stat_t* s,
const bool second) {
const ptrdiff_t offset =
second ? static_cast<ptrdiff_t>(FsStatsOffset::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 AliasedBufferT>
FSReqPromise<AliasedBufferT>*
FSReqPromise<AliasedBufferT>::New(Environment* env, bool use_bigint) {
v8::Local<v8::Object> obj;
if (!env->fsreqpromise_constructor_template()
->NewInstance(env->context())
.ToLocal(&obj)) {
return nullptr;
}
v8::Local<v8::Promise::Resolver> resolver;
if (!v8::Promise::Resolver::New(env->context()).ToLocal(&resolver) ||
obj->Set(env->context(), env->promise_string(), resolver).IsNothing()) {
return nullptr;
}
return new FSReqPromise(env, obj, use_bigint);
}

template <typename AliasedBufferT>
FSReqPromise<AliasedBufferT>::~FSReqPromise() {
// Validate that the promise was explicitly resolved or rejected.
CHECK(finished_);
}

template <typename AliasedBufferT>
FSReqPromise<AliasedBufferT>::FSReqPromise(
Environment* env,
v8::Local<v8::Object> obj,
bool use_bigint)
: FSReqBase(env, obj, AsyncWrap::PROVIDER_FSREQPROMISE, use_bigint),
stats_field_array_(
env->isolate(),
static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber)) {}

template <typename AliasedBufferT>
void FSReqPromise<AliasedBufferT>::Reject(v8::Local<v8::Value> reject) {
finished_ = true;
v8::HandleScope scope(env()->isolate());
InternalCallbackScope callback_scope(this);
v8::Local<v8::Value> value =
object()->Get(env()->context(),
env()->promise_string()).ToLocalChecked();
v8::Local<v8::Promise::Resolver> resolver = value.As<v8::Promise::Resolver>();
USE(resolver->Reject(env()->context(), reject).FromJust());
}

template <typename AliasedBufferT>
void FSReqPromise<AliasedBufferT>::Resolve(v8::Local<v8::Value> value) {
finished_ = true;
v8::HandleScope scope(env()->isolate());
InternalCallbackScope callback_scope(this);
v8::Local<v8::Value> val =
object()->Get(env()->context(),
env()->promise_string()).ToLocalChecked();
v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
USE(resolver->Resolve(env()->context(), value).FromJust());
}

template <typename AliasedBufferT>
void FSReqPromise<AliasedBufferT>::ResolveStat(const uv_stat_t* stat) {
FillStatsArray(&stats_field_array_, stat);
Resolve(stats_field_array_.GetJSArray());
}

template <typename AliasedBufferT>
void FSReqPromise<AliasedBufferT>::SetReturnValue(
const v8::FunctionCallbackInfo<v8::Value>& args) {
v8::Local<v8::Value> val =
object()->Get(env()->context(),
env()->promise_string()).ToLocalChecked();
v8::Local<v8::Promise::Resolver> resolver = val.As<v8::Promise::Resolver>();
args.GetReturnValue().Set(resolver->GetPromise());
}

template <typename AliasedBufferT>
void FSReqPromise<AliasedBufferT>::MemoryInfo(MemoryTracker* tracker) const {
FSReqBase::MemoryInfo(tracker);
tracker->TrackField("stats_field_array", stats_field_array_);
}

FSReqBase* GetReqWrap(Environment* env, v8::Local<v8::Value> value,
bool use_bigint) {
if (value->IsObject()) {
return Unwrap<FSReqBase>(value.As<v8::Object>());
} else if (value->StrictEquals(env->fs_use_promises_symbol())) {
if (use_bigint) {
return FSReqPromise<AliasedBigUint64Array>::New(env, use_bigint);
} else {
return FSReqPromise<AliasedFloat64Array>::New(env, use_bigint);
}
}
return nullptr;
}

// Returns nullptr if the operation fails from the start.
template <typename Func, typename... Args>
FSReqBase* AsyncDestCall(Environment* env, FSReqBase* req_wrap,
const v8::FunctionCallbackInfo<v8::Value>& args,
const char* syscall, const char* dest,
size_t len, enum encoding enc, uv_fs_cb after,
Func fn, Args... fn_args) {
CHECK_NOT_NULL(req_wrap);
req_wrap->Init(syscall, dest, len, enc);
int err = req_wrap->Dispatch(fn, fn_args..., after);
if (err < 0) {
uv_fs_t* uv_req = req_wrap->req();
uv_req->result = err;
uv_req->path = nullptr;
after(uv_req); // after may delete req_wrap if there is an error
req_wrap = nullptr;
} else {
req_wrap->SetReturnValue(args);
}

return req_wrap;
}

// Returns nullptr if the operation fails from the start.
template <typename Func, typename... Args>
FSReqBase* AsyncCall(Environment* env,
FSReqBase* req_wrap,
const v8::FunctionCallbackInfo<v8::Value>& args,
const char* syscall, enum encoding enc,
uv_fs_cb after, Func fn, Args... fn_args) {
return AsyncDestCall(env, req_wrap, args,
syscall, nullptr, 0, enc,
after, fn, fn_args...);
}

// Template counterpart of SYNC_CALL, except that it only puts
// the error number and the syscall in the context instead of
// creating an error in the C++ land.
// ctx must be checked using value->IsObject() before being passed.
template <typename Func, typename... Args>
int SyncCall(Environment* env, v8::Local<v8::Value> ctx,
FSReqWrapSync* req_wrap, const char* syscall,
Func fn, Args... args) {
env->PrintSyncTrace();
int err = fn(env->event_loop(), &(req_wrap->req), args..., nullptr);
if (err < 0) {
v8::Local<v8::Context> context = env->context();
v8::Local<v8::Object> ctx_obj = ctx.As<v8::Object>();
v8::Isolate* isolate = env->isolate();
ctx_obj->Set(context,
env->errno_string(),
v8::Integer::New(isolate, err)).Check();
ctx_obj->Set(context,
env->syscall_string(),
OneByteString(isolate, syscall)).Check();
}
return err;
}

} // namespace fs
} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#endif // SRC_NODE_FILE_INL_H_

0 comments on commit 33064a1

Please sign in to comment.