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

bootstrap: include v8 and fs modules in the startup snapshot #36943

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
bootstrap: include fs module into the builtin snapshot
  • Loading branch information
joyeecheung committed Feb 19, 2021
commit ed19c326f9239044c7131c7241ed31ea0cbb77d9
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