Skip to content

Commit

Permalink
src: snapshot Environment upon instantiation
Browse files Browse the repository at this point in the history
This includes the initial Environment (without running bootstrap
scripts) into the builtin snapshot

PR-URL: #32984
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Daniel Bevenius <daniel.bevenius@gmail.com>
  • Loading branch information
joyeecheung authored and cjihrig committed Jul 22, 2020
1 parent 94b5e21 commit 5b17dba
Show file tree
Hide file tree
Showing 16 changed files with 710 additions and 164 deletions.
66 changes: 57 additions & 9 deletions src/aliased_buffer.h
Expand Up @@ -4,11 +4,14 @@
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

#include <cinttypes>
#include <iostream>
#include "util-inl.h"
#include "v8.h"

namespace node {

typedef size_t AliasedBufferInfo;

/**
* Do not use this class directly when creating instances of it - use the
* Aliased*Array defined at the end of this file instead.
Expand All @@ -32,9 +35,15 @@ template <class NativeT,
typename = std::enable_if_t<std::is_scalar<NativeT>::value>>
class AliasedBufferBase {
public:
AliasedBufferBase(v8::Isolate* isolate, const size_t count)
: isolate_(isolate), count_(count), byte_offset_(0) {
AliasedBufferBase(v8::Isolate* isolate,
const size_t count,
const AliasedBufferInfo* info = nullptr)
: isolate_(isolate), count_(count), byte_offset_(0), info_(info) {
CHECK_GT(count, 0);
if (info != nullptr) {
// Will be deserialized later.
return;
}
const v8::HandleScope handle_scope(isolate_);
const size_t size_in_bytes =
MultiplyWithOverflowCheck(sizeof(NativeT), count);
Expand Down Expand Up @@ -62,10 +71,17 @@ class AliasedBufferBase {
v8::Isolate* isolate,
const size_t byte_offset,
const size_t count,
const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer)
: isolate_(isolate), count_(count), byte_offset_(byte_offset) {
const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer,
const AliasedBufferInfo* info = nullptr)
: isolate_(isolate),
count_(count),
byte_offset_(byte_offset),
info_(info) {
if (info != nullptr) {
// Will be deserialized later.
return;
}
const v8::HandleScope handle_scope(isolate_);

v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer();

// validate that the byte_offset is aligned with sizeof(NativeT)
Expand All @@ -86,10 +102,33 @@ class AliasedBufferBase {
count_(that.count_),
byte_offset_(that.byte_offset_),
buffer_(that.buffer_) {
DCHECK_NULL(info_);
js_array_ = v8::Global<V8T>(that.isolate_, that.GetJSArray());
}

AliasedBufferInfo Serialize(v8::Local<v8::Context> context,
v8::SnapshotCreator* creator) {
DCHECK_NULL(info_);
return creator->AddData(context, GetJSArray());
}

inline void Deserialize(v8::Local<v8::Context> context) {
DCHECK_NOT_NULL(info_);
v8::Local<V8T> arr =
context->GetDataFromSnapshotOnce<V8T>(*info_).ToLocalChecked();
// These may not hold true for AliasedBuffers that have grown, so should
// be removed when we expand the snapshot support.
DCHECK_EQ(count_, arr->Length());
DCHECK_EQ(byte_offset_, arr->ByteOffset());
uint8_t* raw =
static_cast<uint8_t*>(arr->Buffer()->GetBackingStore()->Data());
buffer_ = reinterpret_cast<NativeT*>(raw + byte_offset_);
js_array_.Reset(isolate_, arr);
info_ = nullptr;
}

AliasedBufferBase& operator=(AliasedBufferBase&& that) noexcept {
DCHECK_NULL(info_);
this->~AliasedBufferBase();
isolate_ = that.isolate_;
count_ = that.count_;
Expand Down Expand Up @@ -155,6 +194,7 @@ class AliasedBufferBase {
* Get the underlying v8 TypedArray overlayed on top of the native buffer
*/
v8::Local<V8T> GetJSArray() const {
DCHECK_NULL(info_);
return js_array_.Get(isolate_);
}

Expand All @@ -171,6 +211,7 @@ class AliasedBufferBase {
* through the GetValue/SetValue/operator[] methods
*/
inline const NativeT* GetNativeBuffer() const {
DCHECK_NULL(info_);
return buffer_;
}

Expand All @@ -186,13 +227,15 @@ class AliasedBufferBase {
*/
inline void SetValue(const size_t index, NativeT value) {
DCHECK_LT(index, count_);
DCHECK_NULL(info_);
buffer_[index] = value;
}

/**
* Get value at position index
*/
inline const NativeT GetValue(const size_t index) const {
DCHECK_NULL(info_);
DCHECK_LT(index, count_);
return buffer_[index];
}
Expand All @@ -201,6 +244,7 @@ class AliasedBufferBase {
* Effectively, a synonym for GetValue/SetValue
*/
Reference operator[](size_t index) {
DCHECK_NULL(info_);
return Reference(this, index);
}

Expand All @@ -216,6 +260,7 @@ class AliasedBufferBase {
// Should only be used on an owning array, not one created as a sub array of
// an owning `AliasedBufferBase`.
void reserve(size_t new_capacity) {
DCHECK_NULL(info_);
DCHECK_GE(new_capacity, count_);
DCHECK_EQ(byte_offset_, 0);
const v8::HandleScope handle_scope(isolate_);
Expand Down Expand Up @@ -244,11 +289,14 @@ class AliasedBufferBase {
}

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_;

// Deserialize data
const AliasedBufferInfo* info_ = nullptr;
};

typedef AliasedBufferBase<int32_t, v8::Int32Array> AliasedInt32Array;
Expand Down
8 changes: 1 addition & 7 deletions src/api/environment.cc
Expand Up @@ -350,13 +350,7 @@ Environment* CreateEnvironment(
// TODO(addaleax): This is a much better place for parsing per-Environment
// options than the global parse call.
Environment* env = new Environment(
isolate_data,
context,
args,
exec_args,
flags,
thread_id);
env->InitializeMainContext(context);
isolate_data, context, args, exec_args, nullptr, flags, thread_id);
#if HAVE_INSPECTOR
if (inspector_parent_handle) {
env->InitializeInspector(
Expand Down
3 changes: 2 additions & 1 deletion src/debug_utils.h
Expand Up @@ -46,7 +46,8 @@ void FWrite(FILE* file, const std::string& str);
V(INSPECTOR_PROFILER) \
V(CODE_CACHE) \
V(NGTCP2_DEBUG) \
V(WASI)
V(WASI) \
V(MKSNAPSHOT)

enum class DebugCategory {
#define V(name) name,
Expand Down
29 changes: 0 additions & 29 deletions src/env-inl.h
Expand Up @@ -70,29 +70,6 @@ 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 @@ -277,9 +254,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 @@ -304,9 +278,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

0 comments on commit 5b17dba

Please sign in to comment.