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 all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 9 additions & 5 deletions lib/fs.js
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
4 changes: 4 additions & 0 deletions lib/internal/bootstrap/node.js
Expand Up @@ -347,6 +347,10 @@ 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');
require('v8');

function setupPrepareStackTrace() {
const {
setEnhanceStackForFatalException,
Expand Down
15 changes: 8 additions & 7 deletions lib/v8.js
Expand Up @@ -72,12 +72,13 @@ function getHeapSnapshot() {
return new HeapSnapshotStream(handle);
}

// We need to get the buffer from the binding at the callsite since
// it's re-initialized after deserialization.
const binding = internalBinding('v8');

const {
cachedDataVersionTag,
setFlagsFromString: _setFlagsFromString,
heapStatisticsBuffer,
heapSpaceStatisticsBuffer,
heapCodeStatisticsBuffer,
updateHeapStatisticsBuffer,
updateHeapSpaceStatisticsBuffer,
updateHeapCodeStatisticsBuffer,
Expand Down Expand Up @@ -106,7 +107,7 @@ const {
kCodeAndMetadataSizeIndex,
kBytecodeAndMetadataSizeIndex,
kExternalScriptSourceSizeIndex
} = internalBinding('v8');
} = binding;

const kNumberOfHeapSpaces = kHeapSpaces.length;

Expand All @@ -116,7 +117,7 @@ function setFlagsFromString(flags) {
}

function getHeapStatistics() {
const buffer = heapStatisticsBuffer;
const buffer = binding.heapStatisticsBuffer;

updateHeapStatisticsBuffer();

Expand All @@ -137,7 +138,7 @@ function getHeapStatistics() {

function getHeapSpaceStatistics() {
const heapSpaceStatistics = new Array(kNumberOfHeapSpaces);
const buffer = heapSpaceStatisticsBuffer;
const buffer = binding.heapSpaceStatisticsBuffer;

for (let i = 0; i < kNumberOfHeapSpaces; i++) {
updateHeapSpaceStatisticsBuffer(i);
Expand All @@ -154,7 +155,7 @@ function getHeapSpaceStatistics() {
}

function getHeapCodeStatistics() {
const buffer = heapCodeStatisticsBuffer;
const buffer = binding.heapCodeStatisticsBuffer;

updateHeapCodeStatisticsBuffer();
return {
Expand Down
5 changes: 5 additions & 0 deletions src/aliased_buffer.h
Expand Up @@ -198,6 +198,11 @@ class AliasedBufferBase {
return js_array_.Get(isolate_);
}

void Release() {
DCHECK_NULL(index_);
js_array_.Reset();
}

/**
* Get the underlying v8::ArrayBuffer underlying the TypedArray and
* overlaying the native buffer
Expand Down
4 changes: 4 additions & 0 deletions src/base_object.h
Expand Up @@ -158,6 +158,9 @@ class BaseObject : public MemoryRetainer {

virtual inline void OnGCCollect();

bool is_snapshotable() const { return is_snapshotable_; }
void set_is_snapshotable(bool val) { is_snapshotable_ = val; }

private:
v8::Local<v8::Object> WrappedObject() const override;
bool IsRootNode() const override;
Expand Down Expand Up @@ -206,6 +209,7 @@ class BaseObject : public MemoryRetainer {

Environment* env_;
PointerData* pointer_data_ = nullptr;
bool is_snapshotable_ = false;
};

// Global alias for FromJSObject() to avoid churn.
Expand Down
11 changes: 11 additions & 0 deletions src/env-inl.h
Expand Up @@ -1085,6 +1085,17 @@ void Environment::ForEachBaseObject(T&& iterator) {
}
}

template <typename T>
void Environment::ForEachBindingData(T&& iterator) {
BindingDataStore* map = static_cast<BindingDataStore*>(
context()->GetAlignedPointerFromEmbedderData(
ContextEmbedderIndex::kBindingListIndex));
DCHECK_NOT_NULL(map);
for (auto& it : *map) {
iterator(it.first, it.second);
}
}

void Environment::modify_base_object_count(int64_t delta) {
base_object_count_ += delta;
}
Expand Down
28 changes: 28 additions & 0 deletions src/env.cc
Expand Up @@ -1251,6 +1251,7 @@ EnvSerializeInfo Environment::Serialize(SnapshotCreator* creator) {
EnvSerializeInfo info;
Local<Context> ctx = context();

SerializeBindingData(this, creator, &info);
// Currently all modules are compiled without cache in builtin snapshot
// builder.
info.native_modules = std::vector<std::string>(
Expand Down Expand Up @@ -1317,6 +1318,9 @@ std::ostream& operator<<(std::ostream& output,

std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i) {
output << "{\n"
<< "// -- bindings begins --\n"
<< i.bindings << ",\n"
<< "// -- bindings ends --\n"
<< "// -- native_modules begins --\n"
<< i.native_modules << ",\n"
<< "// -- native_modules ends --\n"
Expand All @@ -1342,9 +1346,33 @@ std::ostream& operator<<(std::ostream& output, const EnvSerializeInfo& i) {
return output;
}

void Environment::EnqueueDeserializeRequest(DeserializeRequestCallback cb,
Local<Object> holder,
int index,
InternalFieldInfo* info) {
DeserializeRequest request{cb, {isolate(), holder}, index, info};
deserialize_requests_.push_back(std::move(request));
}

void Environment::RunDeserializeRequests() {
HandleScope scope(isolate());
Local<Context> ctx = context();
Isolate* is = isolate();
while (!deserialize_requests_.empty()) {
DeserializeRequest request(std::move(deserialize_requests_.front()));
deserialize_requests_.pop_front();
Local<Object> holder = request.holder.Get(is);
request.cb(ctx, holder, request.index, request.info);
request.holder.Reset();
request.info->Delete();
}
}

void Environment::DeserializeProperties(const EnvSerializeInfo* info) {
Local<Context> ctx = context();

RunDeserializeRequests();

native_modules_in_snapshot = info->native_modules;
async_hooks_.Deserialize(ctx);
immediate_info_.Deserialize(ctx);
Expand Down
26 changes: 26 additions & 0 deletions src/env.h
Expand Up @@ -37,6 +37,7 @@
#include "node_main_instance.h"
#include "node_options.h"
#include "node_perf_common.h"
#include "node_snapshotable.h"
#include "req_wrap.h"
#include "util.h"
#include "uv.h"
Expand Down Expand Up @@ -899,7 +900,22 @@ struct PropInfo {
SnapshotIndex index; // In the snapshot
};

typedef void (*DeserializeRequestCallback)(v8::Local<v8::Context> context,
v8::Local<v8::Object> holder,
int index,
InternalFieldInfo* info);
struct DeserializeRequest {
DeserializeRequestCallback cb;
v8::Global<v8::Object> holder;
int index;
InternalFieldInfo* info = nullptr; // Owned by the request

// Move constructor
DeserializeRequest(DeserializeRequest&& other) = default;
};

struct EnvSerializeInfo {
std::vector<PropInfo> bindings;
std::vector<std::string> native_modules;
AsyncHooks::SerializeInfo async_hooks;
TickInfo::SerializeInfo tick_info;
Expand Down Expand Up @@ -934,6 +950,11 @@ class Environment : public MemoryRetainer {

void PrintAllBaseObjects();
void VerifyNoStrongBaseObjects();
void EnqueueDeserializeRequest(DeserializeRequestCallback cb,
v8::Local<v8::Object> holder,
int index,
InternalFieldInfo* info);
void RunDeserializeRequests();
// Should be called before InitializeInspector()
void InitializeDiagnostics();

Expand Down Expand Up @@ -1371,6 +1392,9 @@ class Environment : public MemoryRetainer {
void AddUnmanagedFd(int fd);
void RemoveUnmanagedFd(int fd);

template <typename T>
void ForEachBindingData(T&& iterator);

private:
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
const char* errmsg);
Expand Down Expand Up @@ -1459,6 +1483,8 @@ class Environment : public MemoryRetainer {
bool is_in_inspector_console_call_ = false;
#endif

std::list<DeserializeRequest> deserialize_requests_;

// handle_wrap_queue_ and req_wrap_queue_ needs to be at a fixed offset from
// the start of the class because it is used by
// src/node_postmortem_metadata.cc to calculate offsets and generate debug
Expand Down
9 changes: 9 additions & 0 deletions src/heap_utils.cc
@@ -1,6 +1,7 @@
#include "diagnosticfilename-inl.h"
#include "env-inl.h"
#include "memory_tracker-inl.h"
#include "node_external_reference.h"
#include "stream_base-inl.h"
#include "util-inl.h"

Expand Down Expand Up @@ -399,7 +400,15 @@ void Initialize(Local<Object> target,
env->SetMethod(target, "createHeapSnapshotStream", CreateHeapSnapshotStream);
}

void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(BuildEmbedderGraph);
registry->Register(TriggerHeapSnapshot);
registry->Register(CreateHeapSnapshotStream);
}

} // namespace heap
} // namespace node

NODE_MODULE_CONTEXT_AWARE_INTERNAL(heap_utils, node::heap::Initialize)
NODE_MODULE_EXTERNAL_REFERENCE(heap_utils,
node::heap::RegisterExternalReferences)
12 changes: 11 additions & 1 deletion src/inspector_profiler.cc
Expand Up @@ -3,8 +3,9 @@
#include "debug_utils-inl.h"
#include "diagnosticfilename-inl.h"
#include "memory_tracker-inl.h"
#include "node_file.h"
#include "node_errors.h"
#include "node_external_reference.h"
#include "node_file.h"
#include "node_internals.h"
#include "util-inl.h"
#include "v8-inspector.h"
Expand Down Expand Up @@ -519,7 +520,16 @@ static void Initialize(Local<Object> target,
env->SetMethod(target, "stopCoverage", StopCoverage);
}

void RegisterExternalReferences(ExternalReferenceRegistry* registry) {
registry->Register(SetCoverageDirectory);
registry->Register(SetSourceMapCacheGetter);
registry->Register(TakeCoverage);
registry->Register(StopCoverage);
}

} // namespace profiler
} // namespace node

NODE_MODULE_CONTEXT_AWARE_INTERNAL(profiler, node::profiler::Initialize)
NODE_MODULE_EXTERNAL_REFERENCE(profiler,
node::profiler::RegisterExternalReferences)
9 changes: 9 additions & 0 deletions src/node_dir.cc
@@ -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)
11 changes: 10 additions & 1 deletion src/node_external_reference.h
Expand Up @@ -53,18 +53,25 @@ class ExternalReferenceRegistry {
V(credentials) \
V(env_var) \
V(errors) \
V(fs) \
V(fs_dir) \
V(handle_wrap) \
V(heap_utils) \
V(messaging) \
V(native_module) \
V(process_methods) \
V(process_object) \
V(task_queue) \
V(url) \
V(util) \
V(serdes) \
V(string_decoder) \
V(stream_wrap) \
V(trace_events) \
V(timers) \
V(types) \
V(uv) \
V(v8) \
V(worker)

#if NODE_HAVE_I18N_SUPPORT
Expand All @@ -74,7 +81,9 @@ class ExternalReferenceRegistry {
#endif // NODE_HAVE_I18N_SUPPORT

#if HAVE_INSPECTOR
#define EXTERNAL_REFERENCE_BINDING_LIST_INSPECTOR(V) V(inspector)
#define EXTERNAL_REFERENCE_BINDING_LIST_INSPECTOR(V) \
V(inspector) \
V(profiler)
#else
#define EXTERNAL_REFERENCE_BINDING_LIST_INSPECTOR(V)
#endif // HAVE_INSPECTOR
Expand Down