Skip to content
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
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%
  • Loading branch information
addaleax committed May 8, 2020
commit 8af28fe6d02aea2a12fd623d92c5c4f8e0e84ad3
1 change: 1 addition & 0 deletions node.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,7 @@
'test/cctest/test_per_process.cc',
'test/cctest/test_platform.cc',
'test/cctest/test_json_utils.cc',
'test/cctest/test_snapshot_support.cc',
'test/cctest/test_sockaddr.cc',
'test/cctest/test_traced_value.cc',
'test/cctest/test_util.cc',
Expand Down
48 changes: 43 additions & 5 deletions src/aliased_buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include <cinttypes>
// TODO(addaleax): There really, really should be an aliased_buffer-inl.h.
#include "snapshot_support-inl.h"
#include "util-inl.h"
#include "v8.h"

Expand All @@ -30,8 +32,10 @@ template <class NativeT,
class V8T,
// SFINAE NativeT to be scalar
typename = std::enable_if_t<std::is_scalar<NativeT>::value>>
class AliasedBufferBase {
class AliasedBufferBase final : public Snapshottable {
public:
AliasedBufferBase() {}

AliasedBufferBase(v8::Isolate* isolate, const size_t count)
: isolate_(isolate), count_(count), byte_offset_(0) {
CHECK_GT(count, 0);
Expand Down Expand Up @@ -243,11 +247,45 @@ class AliasedBufferBase {
count_ = new_capacity;
}

void Serialize(SnapshotCreateData* snapshot_data) const override {
v8::HandleScope handle_scope(isolate_);
snapshot_data->StartWriteEntry("AliasedBuffer");
snapshot_data->WriteUint64(count_);
snapshot_data->WriteUint64(byte_offset_);
v8::Local<V8T> arr = GetJSArray();
snapshot_data->WriteObject(arr->CreationContext(), arr);
snapshot_data->EndWriteEntry();
}

AliasedBufferBase(v8::Local<v8::Context> context,
SnapshotReadData* snapshot_data)
: isolate_(context->GetIsolate()) {
v8::HandleScope handle_scope(isolate_);
uint64_t count, byte_offset;
if (snapshot_data->StartReadEntry("AliasedBuffer").IsNothing() ||
!snapshot_data->ReadUint64().To(&count) ||
!snapshot_data->ReadUint64().To(&byte_offset)) {
return;
}

count_ = count;
byte_offset_ = byte_offset;

v8::Local<V8T> field;
if (!snapshot_data->ReadObject<V8T>(context).To(&field)) return;
js_array_.Reset(isolate_, field);
buffer_ = reinterpret_cast<NativeT*>(static_cast<char*>(
field->Buffer()->GetBackingStore()->Data()) +
byte_offset_);

snapshot_data->EndReadEntry();
}

private:
v8::Isolate* isolate_;
size_t count_;
size_t byte_offset_;
NativeT* buffer_;
v8::Isolate* isolate_ = nullptr;
size_t count_ = 0;
size_t byte_offset_ = 0;
NativeT* buffer_ = nullptr;
v8::Global<V8T> js_array_;
};

Expand Down
10 changes: 9 additions & 1 deletion src/api/environment.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "node_native_module_env.h"
#include "node_platform.h"
#include "node_v8_platform-inl.h"
#include "snapshot_support-inl.h"
#include "uv.h"

#if HAVE_INSPECTOR
Expand Down Expand Up @@ -390,6 +391,12 @@ Environment* CreateEnvironment(
env->set_abort_on_uncaught_exception(false);
}

if (isolate_data->snapshot_data() != nullptr &&
!isolate_data->snapshot_data()->errors().empty()) {
FreeEnvironment(env);
return nullptr;
}

#if HAVE_INSPECTOR
if (inspector_parent_handle) {
env->InitializeInspector(
Expand All @@ -400,7 +407,8 @@ Environment* CreateEnvironment(
}
#endif

if (env->RunBootstrapping().IsEmpty()) {
if (env->isolate_data()->snapshot_data() == nullptr &&
env->RunBootstrapping().IsEmpty()) {
FreeEnvironment(env);
return nullptr;
}
Expand Down
1 change: 1 addition & 0 deletions src/base_object-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Environment* BaseObject::env() const {
}

BaseObject* BaseObject::FromJSObject(v8::Local<v8::Value> value) {
DCHECK(value->IsObject());
v8::Local<v8::Object> obj = value.As<v8::Object>();
DCHECK_GE(obj->InternalFieldCount(), BaseObject::kSlot);
return static_cast<BaseObject*>(
Expand Down
8 changes: 7 additions & 1 deletion src/base_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include "memory_tracker.h"
#include "snapshot_support.h"
#include "v8.h"
#include <type_traits> // std::remove_reference

Expand All @@ -34,7 +35,7 @@ class Environment;
template <typename T, bool kIsWeak>
class BaseObjectPtrImpl;

class BaseObject : public MemoryRetainer {
class BaseObject : public MemoryRetainer, public Snapshottable {
public:
enum InternalFields { kSlot, kInternalFieldCount };

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

static v8::StartupData SerializeInternalFields(
v8::Local<v8::Object> object, int index, void* data);
virtual v8::StartupData SerializeInternalFields(
int index, SnapshotCreateData* snapshot_data) const;

protected:
virtual inline void OnGCCollect();

Expand Down
57 changes: 26 additions & 31 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,33 +73,14 @@ inline worker::Worker* IsolateData::worker_context() const {
return worker_context_;
}

SnapshotReadData* IsolateData::snapshot_data() const {
return snapshot_data_;
}

inline v8::Local<v8::String> IsolateData::async_wrap_provider(int index) const {
return async_wrap_providers_[index].Get(isolate_);
}

inline AsyncHooks::AsyncHooks()
: async_ids_stack_(env()->isolate(), 16 * 2),
fields_(env()->isolate(), kFieldsCount),
async_id_fields_(env()->isolate(), kUidFieldsCount) {
clear_async_id_stack();

// Always perform async_hooks checks, not just when async_hooks is enabled.
// TODO(AndreasMadsen): Consider removing this for LTS releases.
// See discussion in https://github.com/nodejs/node/pull/15454
// When removing this, do it by reverting the commit. Otherwise the test
// and flag changes won't be included.
fields_[kCheck] = 1;

// kDefaultTriggerAsyncId should be -1, this indicates that there is no
// specified default value and it should fallback to the executionAsyncId.
// 0 is not used as the magic value, because that indicates a missing context
// which is different from a default context.
async_id_fields_[AsyncHooks::kDefaultTriggerAsyncId] = -1;

// kAsyncIdCounter should start at 1 because that'll be the id the execution
// context during bootstrap (code that runs before entering uv_run()).
async_id_fields_[AsyncHooks::kAsyncIdCounter] = 1;
}
inline AliasedUint32Array& AsyncHooks::fields() {
return fields_;
}
Expand Down Expand Up @@ -128,6 +109,10 @@ inline Environment* AsyncHooks::env() {
return Environment::ForAsyncHooks(this);
}

inline const Environment* AsyncHooks::env() const {
return Environment::ForAsyncHooks(const_cast<AsyncHooks*>(this));
}

// Remember to keep this code aligned with pushAsyncContext() in JS.
inline void AsyncHooks::push_async_context(double async_id,
double trigger_async_id,
Expand Down Expand Up @@ -238,9 +223,6 @@ inline void Environment::PopAsyncCallbackScope() {
async_callback_scope_depth_--;
}

inline ImmediateInfo::ImmediateInfo(v8::Isolate* isolate)
: fields_(isolate, kFieldsCount) {}

inline AliasedUint32Array& ImmediateInfo::fields() {
return fields_;
}
Expand All @@ -265,9 +247,6 @@ inline void ImmediateInfo::ref_count_dec(uint32_t decrement) {
fields_[kRefCount] -= decrement;
}

inline TickInfo::TickInfo(v8::Isolate* isolate)
: fields_(isolate, kFieldsCount) {}

inline AliasedUint8Array& TickInfo::fields() {
return fields_;
}
Expand Down Expand Up @@ -467,15 +446,27 @@ inline void Environment::set_is_in_inspector_console_call(bool value) {
}
#endif

inline const AsyncHooks* Environment::async_hooks() const {
return &async_hooks_;
}

inline AsyncHooks* Environment::async_hooks() {
return &async_hooks_;
}

inline const ImmediateInfo* Environment::immediate_info() const {
return &immediate_info_;
}

inline ImmediateInfo* Environment::immediate_info() {
return &immediate_info_;
}

inline TickInfo* Environment::tick_info() {
inline const TickInfo* Environment::tick_info() const {
return &tick_info_;
}

inline TickInfo* Environment::tick_info() {
return &tick_info_;
}

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

const performance::PerformanceState* Environment::performance_state() const {
return performance_state_.get();
}

inline std::unordered_map<std::string, uint64_t>*
Environment::performance_marks() {
return &performance_marks_;
Expand Down Expand Up @@ -1213,7 +1208,7 @@ BaseObject* CleanupHookCallback::GetBaseObject() const {
}

template <typename T>
void Environment::ForEachBaseObject(T&& iterator) {
void Environment::ForEachBaseObject(T&& iterator) const {
for (const auto& hook : cleanup_hooks_) {
BaseObject* obj = hook.GetBaseObject();
if (obj != nullptr)
Expand Down
Loading