Skip to content

Commit 8af28fe

Browse files
committed
src: include Environment in snapshot
This snapshots a lot more data for startup than what we did previously for increased startup performance. confidence improvement accuracy (*) (**) (***) misc/startup.js mode='process' script='benchmark/fixtures/require-cachable' dur=1 *** 9.73 % ±3.78% ±5.03% ±6.54% misc/startup.js mode='process' script='test/fixtures/semicolon' dur=1 *** 36.11 % ±3.91% ±5.23% ±6.86%
1 parent 4bc3d2c commit 8af28fe

25 files changed

+1507
-152
lines changed

node.gyp

+1
Original file line numberDiff line numberDiff line change
@@ -1157,6 +1157,7 @@
11571157
'test/cctest/test_per_process.cc',
11581158
'test/cctest/test_platform.cc',
11591159
'test/cctest/test_json_utils.cc',
1160+
'test/cctest/test_snapshot_support.cc',
11601161
'test/cctest/test_sockaddr.cc',
11611162
'test/cctest/test_traced_value.cc',
11621163
'test/cctest/test_util.cc',

src/aliased_buffer.h

+43-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

66
#include <cinttypes>
7+
// TODO(addaleax): There really, really should be an aliased_buffer-inl.h.
8+
#include "snapshot_support-inl.h"
79
#include "util-inl.h"
810
#include "v8.h"
911

@@ -30,8 +32,10 @@ template <class NativeT,
3032
class V8T,
3133
// SFINAE NativeT to be scalar
3234
typename = std::enable_if_t<std::is_scalar<NativeT>::value>>
33-
class AliasedBufferBase {
35+
class AliasedBufferBase final : public Snapshottable {
3436
public:
37+
AliasedBufferBase() {}
38+
3539
AliasedBufferBase(v8::Isolate* isolate, const size_t count)
3640
: isolate_(isolate), count_(count), byte_offset_(0) {
3741
CHECK_GT(count, 0);
@@ -243,11 +247,45 @@ class AliasedBufferBase {
243247
count_ = new_capacity;
244248
}
245249

250+
void Serialize(SnapshotCreateData* snapshot_data) const override {
251+
v8::HandleScope handle_scope(isolate_);
252+
snapshot_data->StartWriteEntry("AliasedBuffer");
253+
snapshot_data->WriteUint64(count_);
254+
snapshot_data->WriteUint64(byte_offset_);
255+
v8::Local<V8T> arr = GetJSArray();
256+
snapshot_data->WriteObject(arr->CreationContext(), arr);
257+
snapshot_data->EndWriteEntry();
258+
}
259+
260+
AliasedBufferBase(v8::Local<v8::Context> context,
261+
SnapshotReadData* snapshot_data)
262+
: isolate_(context->GetIsolate()) {
263+
v8::HandleScope handle_scope(isolate_);
264+
uint64_t count, byte_offset;
265+
if (snapshot_data->StartReadEntry("AliasedBuffer").IsNothing() ||
266+
!snapshot_data->ReadUint64().To(&count) ||
267+
!snapshot_data->ReadUint64().To(&byte_offset)) {
268+
return;
269+
}
270+
271+
count_ = count;
272+
byte_offset_ = byte_offset;
273+
274+
v8::Local<V8T> field;
275+
if (!snapshot_data->ReadObject<V8T>(context).To(&field)) return;
276+
js_array_.Reset(isolate_, field);
277+
buffer_ = reinterpret_cast<NativeT*>(static_cast<char*>(
278+
field->Buffer()->GetBackingStore()->Data()) +
279+
byte_offset_);
280+
281+
snapshot_data->EndReadEntry();
282+
}
283+
246284
private:
247-
v8::Isolate* isolate_;
248-
size_t count_;
249-
size_t byte_offset_;
250-
NativeT* buffer_;
285+
v8::Isolate* isolate_ = nullptr;
286+
size_t count_ = 0;
287+
size_t byte_offset_ = 0;
288+
NativeT* buffer_ = nullptr;
251289
v8::Global<V8T> js_array_;
252290
};
253291

src/api/environment.cc

+9-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "node_native_module_env.h"
66
#include "node_platform.h"
77
#include "node_v8_platform-inl.h"
8+
#include "snapshot_support-inl.h"
89
#include "uv.h"
910

1011
#if HAVE_INSPECTOR
@@ -390,6 +391,12 @@ Environment* CreateEnvironment(
390391
env->set_abort_on_uncaught_exception(false);
391392
}
392393

394+
if (isolate_data->snapshot_data() != nullptr &&
395+
!isolate_data->snapshot_data()->errors().empty()) {
396+
FreeEnvironment(env);
397+
return nullptr;
398+
}
399+
393400
#if HAVE_INSPECTOR
394401
if (inspector_parent_handle) {
395402
env->InitializeInspector(
@@ -400,7 +407,8 @@ Environment* CreateEnvironment(
400407
}
401408
#endif
402409

403-
if (env->RunBootstrapping().IsEmpty()) {
410+
if (env->isolate_data()->snapshot_data() == nullptr &&
411+
env->RunBootstrapping().IsEmpty()) {
404412
FreeEnvironment(env);
405413
return nullptr;
406414
}

src/base_object-inl.h

+1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ Environment* BaseObject::env() const {
101101
}
102102

103103
BaseObject* BaseObject::FromJSObject(v8::Local<v8::Value> value) {
104+
DCHECK(value->IsObject());
104105
v8::Local<v8::Object> obj = value.As<v8::Object>();
105106
DCHECK_GE(obj->InternalFieldCount(), BaseObject::kSlot);
106107
return static_cast<BaseObject*>(

src/base_object.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
2626

2727
#include "memory_tracker.h"
28+
#include "snapshot_support.h"
2829
#include "v8.h"
2930
#include <type_traits> // std::remove_reference
3031

@@ -34,7 +35,7 @@ class Environment;
3435
template <typename T, bool kIsWeak>
3536
class BaseObjectPtrImpl;
3637

37-
class BaseObject : public MemoryRetainer {
38+
class BaseObject : public MemoryRetainer, public Snapshottable {
3839
public:
3940
enum InternalFields { kSlot, kInternalFieldCount };
4041

@@ -101,6 +102,11 @@ class BaseObject : public MemoryRetainer {
101102
static v8::Local<v8::FunctionTemplate> GetConstructorTemplate(
102103
Environment* env);
103104

105+
static v8::StartupData SerializeInternalFields(
106+
v8::Local<v8::Object> object, int index, void* data);
107+
virtual v8::StartupData SerializeInternalFields(
108+
int index, SnapshotCreateData* snapshot_data) const;
109+
104110
protected:
105111
virtual inline void OnGCCollect();
106112

src/env-inl.h

+26-31
Original file line numberDiff line numberDiff line change
@@ -73,33 +73,14 @@ inline worker::Worker* IsolateData::worker_context() const {
7373
return worker_context_;
7474
}
7575

76+
SnapshotReadData* IsolateData::snapshot_data() const {
77+
return snapshot_data_;
78+
}
79+
7680
inline v8::Local<v8::String> IsolateData::async_wrap_provider(int index) const {
7781
return async_wrap_providers_[index].Get(isolate_);
7882
}
7983

80-
inline AsyncHooks::AsyncHooks()
81-
: async_ids_stack_(env()->isolate(), 16 * 2),
82-
fields_(env()->isolate(), kFieldsCount),
83-
async_id_fields_(env()->isolate(), kUidFieldsCount) {
84-
clear_async_id_stack();
85-
86-
// Always perform async_hooks checks, not just when async_hooks is enabled.
87-
// TODO(AndreasMadsen): Consider removing this for LTS releases.
88-
// See discussion in https://github.com/nodejs/node/pull/15454
89-
// When removing this, do it by reverting the commit. Otherwise the test
90-
// and flag changes won't be included.
91-
fields_[kCheck] = 1;
92-
93-
// kDefaultTriggerAsyncId should be -1, this indicates that there is no
94-
// specified default value and it should fallback to the executionAsyncId.
95-
// 0 is not used as the magic value, because that indicates a missing context
96-
// which is different from a default context.
97-
async_id_fields_[AsyncHooks::kDefaultTriggerAsyncId] = -1;
98-
99-
// kAsyncIdCounter should start at 1 because that'll be the id the execution
100-
// context during bootstrap (code that runs before entering uv_run()).
101-
async_id_fields_[AsyncHooks::kAsyncIdCounter] = 1;
102-
}
10384
inline AliasedUint32Array& AsyncHooks::fields() {
10485
return fields_;
10586
}
@@ -128,6 +109,10 @@ inline Environment* AsyncHooks::env() {
128109
return Environment::ForAsyncHooks(this);
129110
}
130111

112+
inline const Environment* AsyncHooks::env() const {
113+
return Environment::ForAsyncHooks(const_cast<AsyncHooks*>(this));
114+
}
115+
131116
// Remember to keep this code aligned with pushAsyncContext() in JS.
132117
inline void AsyncHooks::push_async_context(double async_id,
133118
double trigger_async_id,
@@ -238,9 +223,6 @@ inline void Environment::PopAsyncCallbackScope() {
238223
async_callback_scope_depth_--;
239224
}
240225

241-
inline ImmediateInfo::ImmediateInfo(v8::Isolate* isolate)
242-
: fields_(isolate, kFieldsCount) {}
243-
244226
inline AliasedUint32Array& ImmediateInfo::fields() {
245227
return fields_;
246228
}
@@ -265,9 +247,6 @@ inline void ImmediateInfo::ref_count_dec(uint32_t decrement) {
265247
fields_[kRefCount] -= decrement;
266248
}
267249

268-
inline TickInfo::TickInfo(v8::Isolate* isolate)
269-
: fields_(isolate, kFieldsCount) {}
270-
271250
inline AliasedUint8Array& TickInfo::fields() {
272251
return fields_;
273252
}
@@ -467,15 +446,27 @@ inline void Environment::set_is_in_inspector_console_call(bool value) {
467446
}
468447
#endif
469448

449+
inline const AsyncHooks* Environment::async_hooks() const {
450+
return &async_hooks_;
451+
}
452+
470453
inline AsyncHooks* Environment::async_hooks() {
471454
return &async_hooks_;
472455
}
473456

457+
inline const ImmediateInfo* Environment::immediate_info() const {
458+
return &immediate_info_;
459+
}
460+
474461
inline ImmediateInfo* Environment::immediate_info() {
475462
return &immediate_info_;
476463
}
477464

478-
inline TickInfo* Environment::tick_info() {
465+
inline const TickInfo* Environment::tick_info() const {
466+
return &tick_info_;
467+
}
468+
469+
inline TickInfo* Environment::tick_info() {
479470
return &tick_info_;
480471
}
481472

@@ -926,6 +917,10 @@ inline performance::PerformanceState* Environment::performance_state() {
926917
return performance_state_.get();
927918
}
928919

920+
const performance::PerformanceState* Environment::performance_state() const {
921+
return performance_state_.get();
922+
}
923+
929924
inline std::unordered_map<std::string, uint64_t>*
930925
Environment::performance_marks() {
931926
return &performance_marks_;
@@ -1213,7 +1208,7 @@ BaseObject* CleanupHookCallback::GetBaseObject() const {
12131208
}
12141209

12151210
template <typename T>
1216-
void Environment::ForEachBaseObject(T&& iterator) {
1211+
void Environment::ForEachBaseObject(T&& iterator) const {
12171212
for (const auto& hook : cleanup_hooks_) {
12181213
BaseObject* obj = hook.GetBaseObject();
12191214
if (obj != nullptr)

0 commit comments

Comments
 (0)