Skip to content

Commit

Permalink
bootstrap: include fs module into the builtin snapshot
Browse files Browse the repository at this point in the history
PR-URL: #36943
Fixes: #35930
Refs: #35711
Reviewed-By: James M Snell <[email protected]>
  • Loading branch information
joyeecheung committed Feb 19, 2021
1 parent 3c8290c commit 8aa9b77
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 26 deletions.
14 changes: 9 additions & 5 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ const {

const pathModule = require('path');
const { isArrayBufferView } = require('internal/util/types');

// We need to get the statValues from the binding at the callsite since
// it's re-initialized after deserialization.

const binding = internalBinding('fs');
const { Buffer } = require('buffer');
const {
Expand All @@ -81,7 +85,7 @@ const {
uvException
} = require('internal/errors');

const { FSReqCallback, statValues } = binding;
const { FSReqCallback } = binding;
const { toPathIfFileURL } = require('internal/url');
const internalUtil = require('internal/util');
const {
Expand Down Expand Up @@ -1772,8 +1776,8 @@ function realpathSync(p, options) {

// Continue if not a symlink, break if a pipe/socket
if (knownHard[base] || cache?.get(base) === base) {
if (isFileType(statValues, S_IFIFO) ||
isFileType(statValues, S_IFSOCK)) {
if (isFileType(binding.statValues, S_IFIFO) ||
isFileType(binding.statValues, S_IFSOCK)) {
break;
}
continue;
Expand Down Expand Up @@ -1915,8 +1919,8 @@ function realpath(p, options, callback) {

// Continue if not a symlink, break if a pipe/socket
if (knownHard[base]) {
if (isFileType(statValues, S_IFIFO) ||
isFileType(statValues, S_IFSOCK)) {
if (isFileType(binding.statValues, S_IFIFO) ||
isFileType(binding.statValues, S_IFSOCK)) {
return callback(null, encodeRealpathResult(p, options));
}
return process.nextTick(LOOP);
Expand Down
3 changes: 3 additions & 0 deletions lib/internal/bootstrap/node.js
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,9 @@ process.emitWarning = emitWarning;
// Note: only after this point are the timers effective
}

// Preload modules so that they are included in the builtin snapshot.
require('fs');

function setupPrepareStackTrace() {
const {
setEnhanceStackForFatalException,
Expand Down
9 changes: 9 additions & 0 deletions src/node_dir.cc
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "node_dir.h"
#include "node_external_reference.h"
#include "node_file-inl.h"
#include "node_process.h"
#include "memory_tracker-inl.h"
Expand Down Expand Up @@ -364,8 +365,16 @@ void Initialize(Local<Object> target,
env->set_dir_instance_template(dirt);
}

void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(OpenDir);
registry->Register(DirHandle::New);
registry->Register(DirHandle::Read);
registry->Register(DirHandle::Close);
}

} // namespace fs_dir

} // end namespace node

NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs_dir, node::fs_dir::Initialize)
NODE_MODULE_EXTERNAL_REFERENCE(fs_dir, node::fs_dir::RegisterExternalReferences)
2 changes: 2 additions & 0 deletions src/node_external_reference.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ class ExternalReferenceRegistry {
V(credentials) \
V(env_var) \
V(errors) \
V(fs) \
V(fs_dir) \
V(handle_wrap) \
V(messaging) \
V(native_module) \
Expand Down
104 changes: 96 additions & 8 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "aliased_buffer.h"
#include "memory_tracker-inl.h"
#include "node_buffer.h"
#include "node_external_reference.h"
#include "node_process.h"
#include "node_stat_watcher.h"
#include "util-inl.h"
Expand Down Expand Up @@ -2398,6 +2399,47 @@ void BindingData::MemoryInfo(MemoryTracker* tracker) const {
file_handle_read_wrap_freelist);
}

BindingData::BindingData(Environment* env, v8::Local<v8::Object> wrap)
: SnapshotableObject(env, wrap, type_int),
stats_field_array(env->isolate(), kFsStatsBufferLength),
stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) {
wrap->Set(env->context(),
FIXED_ONE_BYTE_STRING(env->isolate(), "statValues"),
stats_field_array.GetJSArray())
.Check();

wrap->Set(env->context(),
FIXED_ONE_BYTE_STRING(env->isolate(), "bigintStatValues"),
stats_field_bigint_array.GetJSArray())
.Check();
}

void BindingData::Deserialize(Local<Context> context,
Local<Object> holder,
int index,
InternalFieldInfo* info) {
DCHECK_EQ(index, BaseObject::kSlot);
HandleScope scope(context->GetIsolate());
Environment* env = Environment::GetCurrent(context);
BindingData* binding = env->AddBindingData<BindingData>(context, holder);
CHECK_NOT_NULL(binding);
}

void BindingData::PrepareForSerialization(Local<Context> context,
v8::SnapshotCreator* creator) {
CHECK(file_handle_read_wrap_freelist.empty());
// We'll just re-initialize the buffers in the constructor since their
// contents can be thrown away once consumed in the previous call.
stats_field_array.Release();
stats_field_bigint_array.Release();
}

InternalFieldInfo* BindingData::Serialize(int index) {
DCHECK_EQ(index, BaseObject::kSlot);
InternalFieldInfo* info = InternalFieldInfo::New(type());
return info;
}

// TODO(addaleax): Remove once we're on C++17.
constexpr FastStringKey BindingData::type_name;

Expand Down Expand Up @@ -2461,14 +2503,6 @@ void Initialize(Local<Object> target,
static_cast<int32_t>(FsStatsOffset::kFsStatsFieldsNumber)))
.Check();

target->Set(context,
FIXED_ONE_BYTE_STRING(isolate, "statValues"),
binding_data->stats_field_array.GetJSArray()).Check();

target->Set(context,
FIXED_ONE_BYTE_STRING(isolate, "bigintStatValues"),
binding_data->stats_field_bigint_array.GetJSArray()).Check();

StatWatcher::Initialize(env, target);

// Create FunctionTemplate for FSReqCallback
Expand Down Expand Up @@ -2532,8 +2566,62 @@ void Initialize(Local<Object> target,
BindingData* FSReqBase::binding_data() {
return binding_data_.get();
}

void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(Access);
StatWatcher::RegisterExternalReferences(registry);

registry->Register(Close);
registry->Register(Open);
registry->Register(OpenFileHandle);
registry->Register(Read);
registry->Register(ReadBuffers);
registry->Register(Fdatasync);
registry->Register(Fsync);
registry->Register(Rename);
registry->Register(FTruncate);
registry->Register(RMDir);
registry->Register(MKDir);
registry->Register(ReadDir);
registry->Register(InternalModuleReadJSON);
registry->Register(InternalModuleStat);
registry->Register(Stat);
registry->Register(LStat);
registry->Register(FStat);
registry->Register(Link);
registry->Register(Symlink);
registry->Register(ReadLink);
registry->Register(Unlink);
registry->Register(WriteBuffer);
registry->Register(WriteBuffers);
registry->Register(WriteString);
registry->Register(RealPath);
registry->Register(CopyFile);

registry->Register(Chmod);
registry->Register(FChmod);
// registry->Register(LChmod);

registry->Register(Chown);
registry->Register(FChown);
registry->Register(LChown);

registry->Register(UTimes);
registry->Register(FUTimes);
registry->Register(LUTimes);

registry->Register(Mkdtemp);
registry->Register(NewFSReqCallback);

registry->Register(FileHandle::New);
registry->Register(FileHandle::Close);
registry->Register(FileHandle::ReleaseFD);
StreamBase::RegisterExternalReferences(registry);
}

} // namespace fs

} // end namespace node

NODE_MODULE_CONTEXT_AWARE_INTERNAL(fs, node::fs::Initialize)
NODE_MODULE_EXTERNAL_REFERENCE(fs, node::fs::RegisterExternalReferences)
15 changes: 7 additions & 8 deletions src/node_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,30 @@

#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "node.h"
#include "aliased_buffer.h"
#include "node_messaging.h"
#include "node_snapshotable.h"
#include "stream_base.h"
#include <iostream>

namespace node {
namespace fs {

class FileHandleReadWrap;

class BindingData : public BaseObject {
class BindingData : public SnapshotableObject {
public:
explicit BindingData(Environment* env, v8::Local<v8::Object> wrap)
: BaseObject(env, wrap),
stats_field_array(env->isolate(), kFsStatsBufferLength),
stats_field_bigint_array(env->isolate(), kFsStatsBufferLength) {}
explicit BindingData(Environment* env, v8::Local<v8::Object> wrap);

AliasedFloat64Array stats_field_array;
AliasedBigUint64Array stats_field_bigint_array;

std::vector<BaseObjectPtr<FileHandleReadWrap>>
file_handle_read_wrap_freelist;

static constexpr FastStringKey type_name { "fs" };
SERIALIZABLE_OBJECT_METHODS()
static constexpr FastStringKey type_name{"node::fs::BindingData"};
static constexpr EmbedderObjectType type_int =
EmbedderObjectType::k_fs_binding_data;

void MemoryInfo(MemoryTracker* tracker) const override;
SET_SELF_SIZE(BindingData)
Expand Down
3 changes: 2 additions & 1 deletion src/node_snapshotable.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ namespace node {
class Environment;
struct EnvSerializeInfo;

#define SERIALIZABLE_OBJECT_TYPES(V)
#define SERIALIZABLE_OBJECT_TYPES(V) \
V(fs_binding_data, fs::BindingData)

enum class EmbedderObjectType : uint8_t {
k_default = 0,
Expand Down
8 changes: 7 additions & 1 deletion src/node_stat_watcher.cc
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,11 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "memory_tracker-inl.h"
#include "node_stat_watcher.h"
#include "async_wrap-inl.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "node_external_reference.h"
#include "node_file-inl.h"
#include "util-inl.h"

Expand Down Expand Up @@ -55,6 +56,11 @@ void StatWatcher::Initialize(Environment* env, Local<Object> target) {
env->SetConstructorFunction(target, "StatWatcher", t);
}

void StatWatcher::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(StatWatcher::New);
registry->Register(StatWatcher::Start);
}

StatWatcher::StatWatcher(fs::BindingData* binding_data,
Local<Object> wrap,
Expand Down
2 changes: 2 additions & 0 deletions src/node_stat_watcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ class BindingData;
}

class Environment;
class ExternalReferenceRegistry;

class StatWatcher : public HandleWrap {
public:
static void Initialize(Environment* env, v8::Local<v8::Object> target);
static void RegisterExternalReferences(ExternalReferenceRegistry* registry);

protected:
StatWatcher(fs::BindingData* binding_data,
Expand Down
28 changes: 26 additions & 2 deletions src/stream_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@
#include "stream_wrap.h"
#include "allocated_buffer-inl.h"

#include "env-inl.h"
#include "js_stream.h"
#include "node.h"
#include "node_buffer.h"
#include "node_errors.h"
#include "env-inl.h"
#include "js_stream.h"
#include "node_external_reference.h"
#include "string_bytes.h"
#include "util-inl.h"
#include "v8.h"
Expand Down Expand Up @@ -423,6 +424,29 @@ void StreamBase::AddMethods(Environment* env, Local<FunctionTemplate> t) {
&Value::IsFunction>);
}

void StreamBase::RegisterExternalReferences(
ExternalReferenceRegistry* registry) {
registry->Register(GetFD);
registry->Register(GetExternal);
registry->Register(GetBytesRead);
registry->Register(GetBytesWritten);
registry->Register(JSMethod<&StreamBase::ReadStartJS>);
registry->Register(JSMethod<&StreamBase::ReadStopJS>);
registry->Register(JSMethod<&StreamBase::Shutdown>);
registry->Register(JSMethod<&StreamBase::UseUserBuffer>);
registry->Register(JSMethod<&StreamBase::Writev>);
registry->Register(JSMethod<&StreamBase::WriteBuffer>);
registry->Register(JSMethod<&StreamBase::WriteString<ASCII>>);
registry->Register(JSMethod<&StreamBase::WriteString<UTF8>>);
registry->Register(JSMethod<&StreamBase::WriteString<UCS2>>);
registry->Register(JSMethod<&StreamBase::WriteString<LATIN1>>);
registry->Register(
BaseObject::InternalFieldGet<StreamBase::kOnReadFunctionField>);
registry->Register(
BaseObject::InternalFieldSet<StreamBase::kOnReadFunctionField,
&Value::IsFunction>);
}

void StreamBase::GetFD(const FunctionCallbackInfo<Value>& args) {
// Mimic implementation of StreamBase::GetFD() and UDPWrap::GetFD().
StreamBase* wrap = StreamBase::FromObject(args.This().As<Object>());
Expand Down
3 changes: 2 additions & 1 deletion src/stream_base.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class ShutdownWrap;
class WriteWrap;
class StreamBase;
class StreamResource;
class ExternalReferenceRegistry;

struct StreamWriteResult {
bool async;
Expand Down Expand Up @@ -308,7 +309,7 @@ class StreamBase : public StreamResource {

static void AddMethods(Environment* env,
v8::Local<v8::FunctionTemplate> target);

static void RegisterExternalReferences(ExternalReferenceRegistry* registry);
virtual bool IsAlive() = 0;
virtual bool IsClosing() = 0;
virtual bool IsIPCPipe();
Expand Down

0 comments on commit 8aa9b77

Please sign in to comment.