Skip to content

Commit f3d7a8d

Browse files
committed
src: implement AliasedBufferBase bookkeeping
In addition implement Environment::PrintAllBuffers() and Environment::PrintAllBaseObjects() for bookkeeping.
1 parent 0cc05cd commit f3d7a8d

4 files changed

Lines changed: 156 additions & 23 deletions

File tree

src/aliased_buffer.h

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

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

@@ -26,14 +27,23 @@ namespace node {
2627
* The encapsulation herein provides a placeholder where such writes can be
2728
* observed. Any notification APIs will be left as a future exercise.
2829
*/
30+
31+
enum class AliasedBufferType { kNew, kCopy, kShared, kAssigned };
32+
2933
template <class NativeT,
3034
class V8T,
3135
// SFINAE NativeT to be scalar
32-
typename = std::enable_if_t<std::is_scalar<NativeT>::value>>
36+
typename Trait = std::enable_if_t<std::is_scalar<NativeT>::value>>
3337
class AliasedBufferBase {
3438
public:
35-
AliasedBufferBase(v8::Isolate* isolate, const size_t count)
36-
: isolate_(isolate), count_(count), byte_offset_(0) {
39+
static std::unordered_set<AliasedBufferBase*> buffers;
40+
41+
inline AliasedBufferBase(v8::Isolate* isolate, const size_t count)
42+
: isolate_(isolate),
43+
count_(count),
44+
byte_offset_(0),
45+
type_(AliasedBufferType::kNew) {
46+
buffers.insert(this);
3747
CHECK_GT(count, 0);
3848
const v8::HandleScope handle_scope(isolate_);
3949
const size_t size_in_bytes =
@@ -63,7 +73,11 @@ class AliasedBufferBase {
6373
const size_t byte_offset,
6474
const size_t count,
6575
const AliasedBufferBase<uint8_t, v8::Uint8Array>& backing_buffer)
66-
: isolate_(isolate), count_(count), byte_offset_(byte_offset) {
76+
: isolate_(isolate),
77+
count_(count),
78+
byte_offset_(byte_offset),
79+
type_(AliasedBufferType::kShared) {
80+
buffers.insert(this);
6781
const v8::HandleScope handle_scope(isolate_);
6882

6983
v8::Local<v8::ArrayBuffer> ab = backing_buffer.GetArrayBuffer();
@@ -85,10 +99,14 @@ class AliasedBufferBase {
8599
: isolate_(that.isolate_),
86100
count_(that.count_),
87101
byte_offset_(that.byte_offset_),
88-
buffer_(that.buffer_) {
102+
buffer_(that.buffer_),
103+
type_(AliasedBufferType::kCopy) {
104+
buffers.insert(this);
89105
js_array_ = v8::Global<V8T>(that.isolate_, that.GetJSArray());
90106
}
91107

108+
inline ~AliasedBufferBase() { buffers.erase(this); }
109+
92110
AliasedBufferBase& operator=(AliasedBufferBase&& that) noexcept {
93111
this->~AliasedBufferBase();
94112
isolate_ = that.isolate_;
@@ -97,6 +115,7 @@ class AliasedBufferBase {
97115
buffer_ = that.buffer_;
98116

99117
js_array_.Reset(isolate_, that.js_array_.Get(isolate_));
118+
type_ = AliasedBufferType::kAssigned;
100119

101120
that.buffer_ = nullptr;
102121
that.js_array_.Reset();
@@ -243,19 +262,40 @@ class AliasedBufferBase {
243262
count_ = new_capacity;
244263
}
245264

265+
AliasedBufferType type() const { return type_; }
266+
267+
typedef void (*AliasedBufferIterator)(AliasedBufferBase*, void* data);
268+
269+
static void ForEachBuffer(AliasedBufferIterator iter, void* data) {
270+
for (const auto& item : buffers) {
271+
iter(item, data);
272+
}
273+
}
274+
246275
private:
247276
v8::Isolate* isolate_;
248277
size_t count_;
249278
size_t byte_offset_;
250279
NativeT* buffer_;
251280
v8::Global<V8T> js_array_;
281+
AliasedBufferType type_;
252282
};
253283

254-
typedef AliasedBufferBase<int32_t, v8::Int32Array> AliasedInt32Array;
255-
typedef AliasedBufferBase<uint8_t, v8::Uint8Array> AliasedUint8Array;
256-
typedef AliasedBufferBase<uint32_t, v8::Uint32Array> AliasedUint32Array;
257-
typedef AliasedBufferBase<double, v8::Float64Array> AliasedFloat64Array;
258-
typedef AliasedBufferBase<uint64_t, v8::BigUint64Array> AliasedBigUint64Array;
284+
template <class NativeT, class V8T, typename Trait>
285+
std::unordered_set<AliasedBufferBase<NativeT, V8T, Trait>*>
286+
AliasedBufferBase<NativeT, V8T, Trait>::buffers;
287+
288+
#define ALIASED_BUFFER_TYPES(V) \
289+
V(uint8_t, Uint8Array) \
290+
V(int32_t, Int32Array) \
291+
V(uint32_t, Uint32Array) \
292+
V(double, Float64Array) \
293+
V(uint64_t, BigUint64Array)
294+
295+
#define V(NativeT, V8T) \
296+
typedef AliasedBufferBase<NativeT, v8::V8T> Aliased##V8T;
297+
ALIASED_BUFFER_TYPES(V)
298+
#undef V
259299
} // namespace node
260300

261301
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS

src/env-inl.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,15 +1229,6 @@ BaseObject* CleanupHookCallback::GetBaseObject() const {
12291229
return nullptr;
12301230
}
12311231

1232-
template <typename T>
1233-
void Environment::ForEachBaseObject(T&& iterator) {
1234-
for (const auto& hook : cleanup_hooks_) {
1235-
BaseObject* obj = hook.GetBaseObject();
1236-
if (obj != nullptr)
1237-
iterator(obj);
1238-
}
1239-
}
1240-
12411232
void Environment::modify_base_object_count(int64_t delta) {
12421233
base_object_count_ += delta;
12431234
}

src/env.cc

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <algorithm>
2323
#include <atomic>
2424
#include <cstdio>
25+
#include <iostream>
2526
#include <memory>
2627

2728
namespace node {
@@ -1097,6 +1098,102 @@ Environment* Environment::worker_parent_env() const {
10971098
return worker_context()->env();
10981099
}
10991100

1101+
void Environment::ForEachBaseObject(BaseObjectIterator iterator) {
1102+
size_t i = 0;
1103+
for (const auto& hook : cleanup_hooks_) {
1104+
BaseObject* obj = hook.GetBaseObject();
1105+
if (obj != nullptr) iterator(i, obj);
1106+
i++;
1107+
}
1108+
}
1109+
1110+
void PrintBaseObject(size_t i, BaseObject* obj) {
1111+
std::cout << "#" << i << " " << obj << ": " << obj->MemoryInfoName() << "\n";
1112+
}
1113+
1114+
void Environment::PrintAllBaseObjects() {
1115+
std::cout << "BaseObjects\n";
1116+
ForEachBaseObject(PrintBaseObject);
1117+
}
1118+
1119+
struct PrinterData {
1120+
const std::map<const void*, std::string>* names;
1121+
size_t index = 0;
1122+
};
1123+
1124+
template <typename AliasedBufferBase>
1125+
static void PrintBuffer(AliasedBufferBase* buf, void* data) {
1126+
PrinterData* printer_data = static_cast<PrinterData*>(data);
1127+
std::cout << "#" << printer_data->index++;
1128+
auto it = printer_data->names->find(buf);
1129+
if (it == printer_data->names->end()) {
1130+
std::cout << " Unkonwn " << buf;
1131+
// Require the Environment to register all known AliasedBuffers.
1132+
UNREACHABLE();
1133+
}
1134+
1135+
std::string type_name;
1136+
switch (buf->type()) {
1137+
case AliasedBufferType::kNew:
1138+
type_name = "new";
1139+
break;
1140+
case AliasedBufferType::kCopy:
1141+
type_name = "copy";
1142+
break;
1143+
case AliasedBufferType::kAssigned:
1144+
type_name = "assigned";
1145+
break;
1146+
case AliasedBufferType::kShared:
1147+
type_name = "shared";
1148+
break;
1149+
default:
1150+
UNREACHABLE();
1151+
}
1152+
1153+
std::cout << " " << it->second << "(length=" << buf->Length()
1154+
<< ", address=" << buf << ", type=" << type_name << "): ";
1155+
1156+
size_t len = buf->Length();
1157+
auto buf_data = buf->GetNativeBuffer();
1158+
for (size_t j = 0; j < len; ++j) {
1159+
std::cout << std::to_string(buf_data[j]) << (j == len - 1 ? "\n" : ", ");
1160+
}
1161+
}
1162+
1163+
#define FOR_EACH_KNOWN_BUFFER_IN_ENV(V) \
1164+
V(stream_base_state_, Int32Array) \
1165+
V(performance_state_->root, Uint8Array) \
1166+
V(performance_state_->milestones, Float64Array) \
1167+
V(performance_state_->observers, Uint32Array) \
1168+
V(should_abort_on_uncaught_toggle_, Uint32Array) \
1169+
V(async_hooks_.fields_, Uint32Array) \
1170+
V(async_hooks_.async_ids_stack_, Float64Array) \
1171+
V(async_hooks_.async_id_fields_, Float64Array) \
1172+
V(tick_info_.fields_, Uint8Array) \
1173+
V(immediate_info_.fields_, Uint32Array)
1174+
1175+
std::map<const void*, std::string> Environment::GetKnownBufferNames() const {
1176+
std::map<const void*, std::string> names;
1177+
1178+
#define V(Reference, V8T) names[&(Reference)] = #Reference;
1179+
FOR_EACH_KNOWN_BUFFER_IN_ENV(V)
1180+
#undef V
1181+
1182+
return names;
1183+
}
1184+
1185+
void Environment::PrintAllBuffers() {
1186+
std::map<const void*, std::string> names = GetKnownBufferNames();
1187+
PrinterData printer_data{&names, 0};
1188+
1189+
#define V(NativeT, V8T) \
1190+
std::cout << "Aliased" #V8T << "s\n"; \
1191+
Aliased##V8T::ForEachBuffer(PrintBuffer<Aliased##V8T>, &printer_data); \
1192+
std::cout << "\n";
1193+
ALIASED_BUFFER_TYPES(V)
1194+
#undef V
1195+
}
1196+
11001197
void MemoryTracker::TrackField(const char* edge_name,
11011198
const CleanupHookCallback& value,
11021199
const char* node_name) {

src/env.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <cstdint>
4646
#include <functional>
4747
#include <list>
48+
#include <map>
4849
#include <unordered_map>
4950
#include <unordered_set>
5051
#include <vector>
@@ -862,6 +863,12 @@ class Environment : public MemoryRetainer {
862863
void MemoryInfo(MemoryTracker* tracker) const override;
863864

864865
void CreateProperties();
866+
867+
typedef void (*BaseObjectIterator)(size_t, BaseObject*);
868+
void ForEachBaseObject(BaseObjectIterator iterator);
869+
void PrintAllBaseObjects();
870+
void PrintAllBuffers();
871+
865872
// Should be called before InitializeInspector()
866873
void InitializeDiagnostics();
867874
#if HAVE_INSPECTOR
@@ -1287,7 +1294,8 @@ class Environment : public MemoryRetainer {
12871294
private:
12881295
template <typename Fn>
12891296
inline void CreateImmediate(Fn&& cb, bool ref);
1290-
1297+
1298+
std::map<const void*, std::string> GetKnownBufferNames() const;
12911299
inline void ThrowError(v8::Local<v8::Value> (*fun)(v8::Local<v8::String>),
12921300
const char* errmsg);
12931301

@@ -1476,9 +1484,6 @@ class Environment : public MemoryRetainer {
14761484
std::function<void(Environment*, int)> process_exit_handler_ {
14771485
DefaultProcessExitHandler };
14781486

1479-
template <typename T>
1480-
void ForEachBaseObject(T&& iterator);
1481-
14821487
#define V(PropertyName, TypeName) v8::Global<TypeName> PropertyName ## _;
14831488
ENVIRONMENT_CALLBACK_DATA(V)
14841489
ENVIRONMENT_STRONG_PERSISTENT_VALUES(V)

0 commit comments

Comments
 (0)