Skip to content

Commit 7d0932e

Browse files
committed
src: snapshot Environment upon instantiation
1 parent 94335ab commit 7d0932e

14 files changed

+842
-185
lines changed

src/aliased_buffer.h

Lines changed: 72 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@
44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

66
#include <cinttypes>
7+
#include <iostream>
78
#include "util-inl.h"
89
#include "v8.h"
910

1011
namespace node {
1112

13+
typedef size_t AliasedBufferInfo;
14+
1215
/**
1316
* Do not use this class directly when creating instances of it - use the
1417
* Aliased*Array defined at the end of this file instead.
@@ -26,27 +29,53 @@ namespace node {
2629
* The encapsulation herein provides a placeholder where such writes can be
2730
* observed. Any notification APIs will be left as a future exercise.
2831
*/
32+
2933
template <class NativeT,
3034
class V8T,
3135
// SFINAE NativeT to be scalar
3236
typename = std::enable_if_t<std::is_scalar<NativeT>::value>>
3337
class AliasedBufferBase {
3438
public:
35-
AliasedBufferBase(v8::Isolate* isolate, const size_t count)
39+
AliasedBufferBase(v8::Isolate* isolate,
40+
const size_t count,
41+
const AliasedBufferInfo* info = nullptr)
3642
: isolate_(isolate), count_(count), byte_offset_(0) {
3743
CHECK_GT(count, 0);
3844
const v8::HandleScope handle_scope(isolate_);
39-
const size_t size_in_bytes =
40-
MultiplyWithOverflowCheck(sizeof(NativeT), count);
45+
if (info == nullptr) {
46+
CHECK_GT(count, 0);
47+
const size_t size_in_bytes =
48+
MultiplyWithOverflowCheck(sizeof(NativeT), count);
49+
50+
// allocate v8 ArrayBuffer
51+
v8::Local<v8::ArrayBuffer> ab =
52+
v8::ArrayBuffer::New(isolate_, size_in_bytes);
53+
buffer_ = static_cast<NativeT*>(ab->GetBackingStore()->Data());
54+
55+
// allocate v8 TypedArray
56+
v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, count);
57+
js_array_ = v8::Global<V8T>(isolate, js_array);
58+
} else {
59+
info_ = info;
60+
buffer_ = nullptr;
61+
}
62+
}
4163

42-
// allocate v8 ArrayBuffer
43-
v8::Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(
44-
isolate_, size_in_bytes);
45-
buffer_ = static_cast<NativeT*>(ab->GetBackingStore()->Data());
64+
AliasedBufferInfo Serialize(v8::Local<v8::Context> context,
65+
v8::SnapshotCreator* creator) {
66+
return creator->AddData(context, GetJSArray());
67+
}
4668

47-
// allocate v8 TypedArray
48-
v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, count);
49-
js_array_ = v8::Global<V8T>(isolate, js_array);
69+
inline void Deserialize(v8::Local<v8::Context> context) {
70+
v8::Local<V8T> arr =
71+
context->GetDataFromSnapshotOnce<V8T>(*info_).ToLocalChecked();
72+
CHECK_EQ(count_, arr->Length());
73+
CHECK_EQ(byte_offset_, arr->ByteOffset());
74+
uint8_t* raw =
75+
static_cast<uint8_t*>(arr->Buffer()->GetBackingStore()->Data());
76+
buffer_ = reinterpret_cast<NativeT*>(raw + byte_offset_);
77+
js_array_.Reset(isolate_, arr);
78+
info_ = nullptr;
5079
}
5180

5281
/**
@@ -62,23 +91,29 @@ class AliasedBufferBase {
6291
v8::Isolate* isolate,
6392
const size_t byte_offset,
6493
const size_t count,
65-
const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer)
94+
const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer,
95+
const AliasedBufferInfo* info = nullptr)
6696
: isolate_(isolate), count_(count), byte_offset_(byte_offset) {
6797
const v8::HandleScope handle_scope(isolate_);
6898

69-
v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer();
99+
if (info == nullptr) {
100+
v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer();
70101

71-
// validate that the byte_offset is aligned with sizeof(NativeT)
72-
CHECK_EQ(byte_offset & (sizeof(NativeT) - 1), 0);
73-
// validate this fits inside the backing buffer
74-
CHECK_LE(MultiplyWithOverflowCheck(sizeof(NativeT), count),
75-
ab->ByteLength() - byte_offset);
102+
// validate that the byte_offset is aligned with sizeof(NativeT)
103+
CHECK_EQ(byte_offset_ & (sizeof(NativeT) - 1), 0);
104+
// validate this fits inside the backing buffer
105+
CHECK_LE(MultiplyWithOverflowCheck(sizeof(NativeT), count_),
106+
ab->ByteLength() - byte_offset_);
76107

77-
buffer_ = reinterpret_cast<NativeT*>(
78-
const_cast<uint8_t*>(backing_buffer.GetNativeBuffer() + byte_offset));
108+
buffer_ = reinterpret_cast<NativeT*>(const_cast<uint8_t*>(
109+
backing_buffer.GetNativeBuffer() + byte_offset_));
79110

80-
v8::Local<V8T> js_array = V8T::New(ab, byte_offset, count);
81-
js_array_ = v8::Global<V8T>(isolate, js_array);
111+
v8::Local<V8T> js_array = V8T::New(ab, byte_offset_, count_);
112+
js_array_ = v8::Global<V8T>(isolate_, js_array);
113+
} else {
114+
info_ = info;
115+
buffer_ = nullptr;
116+
}
82117
}
83118

84119
AliasedBufferBase(const AliasedBufferBase& that)
@@ -90,6 +125,7 @@ class AliasedBufferBase {
90125
}
91126

92127
AliasedBufferBase& operator=(AliasedBufferBase&& that) noexcept {
128+
DCHECK_NULL(info_);
93129
this->~AliasedBufferBase();
94130
isolate_ = that.isolate_;
95131
count_ = that.count_;
@@ -155,6 +191,7 @@ class AliasedBufferBase {
155191
* Get the underlying v8 TypedArray overlayed on top of the native buffer
156192
*/
157193
v8::Local<V8T> GetJSArray() const {
194+
DCHECK_NULL(info_);
158195
return js_array_.Get(isolate_);
159196
}
160197

@@ -171,6 +208,7 @@ class AliasedBufferBase {
171208
* through the GetValue/SetValue/operator[] methods
172209
*/
173210
inline const NativeT* GetNativeBuffer() const {
211+
DCHECK_NULL(info_);
174212
return buffer_;
175213
}
176214

@@ -186,13 +224,15 @@ class AliasedBufferBase {
186224
*/
187225
inline void SetValue(const size_t index, NativeT value) {
188226
DCHECK_LT(index, count_);
227+
DCHECK_NULL(info_);
189228
buffer_[index] = value;
190229
}
191230

192231
/**
193232
* Get value at position index
194233
*/
195234
inline const NativeT GetValue(const size_t index) const {
235+
DCHECK_NULL(info_);
196236
DCHECK_LT(index, count_);
197237
return buffer_[index];
198238
}
@@ -201,6 +241,7 @@ class AliasedBufferBase {
201241
* Effectively, a synonym for GetValue/SetValue
202242
*/
203243
Reference operator[](size_t index) {
244+
DCHECK_NULL(info_);
204245
return Reference(this, index);
205246
}
206247

@@ -243,12 +284,22 @@ class AliasedBufferBase {
243284
count_ = new_capacity;
244285
}
245286

287+
void Print() {
288+
std::cout << "[ ";
289+
for (size_t i = 0; i < count_; ++i) {
290+
std::cout << std::to_string(buffer_[i])
291+
<< (i == count_ - 1 ? " ]\n" : ", ");
292+
}
293+
}
294+
246295
private:
247296
v8::Isolate* isolate_;
248297
size_t count_;
249298
size_t byte_offset_;
250299
NativeT* buffer_;
251300
v8::Global<V8T> js_array_;
301+
302+
const AliasedBufferInfo* info_ = nullptr;
252303
};
253304

254305
typedef AliasedBufferBase<int32_t, v8::Int32Array> AliasedInt32Array;

src/api/environment.cc

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -368,15 +368,7 @@ Environment* CreateEnvironment(
368368
// TODO(addaleax): This is a much better place for parsing per-Environment
369369
// options than the global parse call.
370370
Environment* env = new Environment(
371-
isolate_data,
372-
context,
373-
args,
374-
exec_args,
375-
flags,
376-
thread_id);
377-
if (flags & EnvironmentFlags::kOwnsProcessState) {
378-
env->set_abort_on_uncaught_exception(false);
379-
}
371+
isolate_data, context, args, exec_args, nullptr, flags, thread_id);
380372

381373
#if HAVE_INSPECTOR
382374
if (inspector_parent_handle) {

src/base_object.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030

3131
namespace node {
3232

33+
enum class InternalFieldType { kDefault = 0, kNoBindingData };
34+
3335
class Environment;
3436
template <typename T, bool kIsWeak>
3537
class BaseObjectPtrImpl;
@@ -98,10 +100,14 @@ class BaseObject : public MemoryRetainer {
98100
// a BaseObjectPtr to this object.
99101
inline void Detach();
100102

103+
InternalFieldType type() { return type_; }
104+
void set_type(InternalFieldType type) { type_ = type; }
105+
101106
protected:
102107
virtual inline void OnGCCollect();
103108

104109
private:
110+
InternalFieldType type_ = InternalFieldType::kDefault;
105111
v8::Local<v8::Object> WrappedObject() const override;
106112
static void DeleteMe(void* data);
107113

src/debug_utils.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ void FWrite(FILE* file, const std::string& str);
4545
V(INSPECTOR_SERVER) \
4646
V(INSPECTOR_PROFILER) \
4747
V(CODE_CACHE) \
48-
V(WASI)
48+
V(WASI) \
49+
V(MKSNAPSHOT)
4950

5051
enum class DebugCategory {
5152
#define V(name) name,

src/env-inl.h

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -77,29 +77,6 @@ inline v8::Local<v8::String> IsolateData::async_wrap_provider(int index) const {
7777
return async_wrap_providers_[index].Get(isolate_);
7878
}
7979

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-
}
10380
inline AliasedUint32Array& AsyncHooks::fields() {
10481
return fields_;
10582
}
@@ -238,9 +215,6 @@ inline void Environment::PopAsyncCallbackScope() {
238215
async_callback_scope_depth_--;
239216
}
240217

241-
inline ImmediateInfo::ImmediateInfo(v8::Isolate* isolate)
242-
: fields_(isolate, kFieldsCount) {}
243-
244218
inline AliasedUint32Array& ImmediateInfo::fields() {
245219
return fields_;
246220
}
@@ -265,9 +239,6 @@ inline void ImmediateInfo::ref_count_dec(uint32_t decrement) {
265239
fields_[kRefCount] -= decrement;
266240
}
267241

268-
inline TickInfo::TickInfo(v8::Isolate* isolate)
269-
: fields_(isolate, kFieldsCount) {}
270-
271242
inline AliasedUint8Array& TickInfo::fields() {
272243
return fields_;
273244
}
@@ -365,16 +336,22 @@ inline v8::Local<v8::Uint32> BindingDataBase::New(
365336
Environment* env,
366337
v8::Local<v8::Context> context,
367338
v8::Local<v8::Object> target) {
368-
T* data = new T(env, target);
339+
return Initialize(context, new T(env, target));
340+
}
341+
342+
template <typename T>
343+
inline v8::Local<v8::Uint32> BindingDataBase::Initialize(
344+
v8::Local<v8::Context> context, T* binding) {
369345
// This won't compile if T is not a BindingDataBase subclass.
370-
BindingDataBase* item = static_cast<BindingDataBase*>(data);
346+
BindingDataBase* item = static_cast<BindingDataBase*>(binding);
371347
std::vector<BindingDataBase*>* list =
372348
static_cast<std::vector<BindingDataBase*>*>(
373349
context->GetAlignedPointerFromEmbedderData(
374350
ContextEmbedderIndex::KBindingListIndex));
375351
size_t index = list->size();
376352
list->push_back(item);
377-
return v8::Integer::NewFromUnsigned(env->isolate(), index).As<v8::Uint32>();
353+
return v8::Integer::NewFromUnsigned(context->GetIsolate(), index)
354+
.As<v8::Uint32>();
378355
}
379356

380357
template <typename T>
@@ -384,7 +361,7 @@ Environment::BindingScope<T>::BindingScope(Environment* env,
384361
: env(env) {
385362
v8::Local<v8::Uint32> index = BindingDataBase::New<T>(env, context, target);
386363
data = BindingDataBase::Unwrap<T>(context, index);
387-
env->set_current_callback_data(index);
364+
env->set_current_callback_data(index.As<v8::Uint32>());
388365
}
389366

390367
template <typename T>

0 commit comments

Comments
 (0)