Skip to content

Commit e4cd81b

Browse files
addaleaxdanielleadams
authored andcommitted
src: use string_view for report and related code
Use `std::string_view` for process.report code and related code, drop a few unnecessary `std::to_string` calls, and use `MaybeStackBuffer` instead of `MallocedBuffer`, all in order to avoid unnecessary heap allocations. PR-URL: #46723 Backport-PR-URL: #47435 Reviewed-By: Tobias Nießen <[email protected]> Reviewed-By: Yagiz Nizipli <[email protected]> Reviewed-By: James M Snell <[email protected]> Reviewed-By: Darshan Sen <[email protected]> Reviewed-By: Chengzhong Wu <[email protected]>
1 parent e5c4d69 commit e4cd81b

7 files changed

+76
-64
lines changed

src/json_utils.cc

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22

33
namespace node {
44

5-
std::string EscapeJsonChars(const std::string& str) {
6-
const std::string control_symbols[0x20] = {
5+
std::string EscapeJsonChars(std::string_view str) {
6+
static const std::string_view control_symbols[0x20] = {
77
"\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005",
88
"\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b",
99
"\\f", "\\r", "\\u000e", "\\u000f", "\\u0010", "\\u0011",

src/json_utils.h

+18-7
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,21 @@
44
#if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
55

66
#include <iomanip>
7-
#include <ostream>
87
#include <limits>
8+
#include <ostream>
99
#include <string>
10+
#include <string_view>
1011

1112
namespace node {
1213

13-
std::string EscapeJsonChars(const std::string& str);
14+
constexpr bool NeedsJsonEscape(std::string_view str) {
15+
for (const char c : str) {
16+
if (c == '\\' || c == '"' || c < 0x20) return true;
17+
}
18+
return false;
19+
}
20+
21+
std::string EscapeJsonChars(std::string_view str);
1422
std::string Reindent(const std::string& str, int indentation);
1523

1624
// JSON compiler definitions.
@@ -135,17 +143,20 @@ class JSONWriter {
135143
}
136144

137145
inline void write_value(Null null) { out_ << "null"; }
138-
inline void write_value(const char* str) { write_string(str); }
139-
inline void write_value(const std::string& str) { write_string(str); }
146+
inline void write_value(std::string_view str) { write_string(str); }
140147

141148
inline void write_value(const ForeignJSON& json) {
142149
out_ << Reindent(json.as_string, indent_);
143150
}
144151

145-
inline void write_string(const std::string& str) {
146-
out_ << '"' << EscapeJsonChars(str) << '"';
152+
inline void write_string(std::string_view str) {
153+
out_ << '"';
154+
if (NeedsJsonEscape(str)) // only create temporary std::string if necessary
155+
out_ << EscapeJsonChars(str);
156+
else
157+
out_ << str;
158+
out_ << '"';
147159
}
148-
inline void write_string(const char* str) { write_string(std::string(str)); }
149160

150161
enum JSONState { kObjectStart, kAfterValue };
151162
std::ostream& out_;

src/node_api.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -657,7 +657,7 @@ void napi_module_register_by_symbol(v8::Local<v8::Object> exports,
657657
// a file system path.
658658
// TODO(gabrielschulhof): Pass the `filename` through unchanged if/when we
659659
// receive it as a URL already.
660-
module_filename = node::url::FromFilePath(filename.ToString());
660+
module_filename = node::url::FromFilePath(filename.ToStringView());
661661
}
662662

663663
// Create a new napi_env for this specific module.

src/node_errors.cc

+4-2
Original file line numberDiff line numberDiff line change
@@ -450,8 +450,10 @@ static void ReportFatalException(Environment* env,
450450
// Not an error object. Just print as-is.
451451
node::Utf8Value message(env->isolate(), error);
452452

453-
FPrintF(stderr, "%s\n",
454-
*message ? message.ToString() : "<toString() threw exception>");
453+
FPrintF(
454+
stderr,
455+
"%s\n",
456+
*message ? message.ToStringView() : "<toString() threw exception>");
455457
} else {
456458
node::Utf8Value name_string(env->isolate(), name.ToLocalChecked());
457459
node::Utf8Value message_string(env->isolate(), message.ToLocalChecked());

src/node_report.cc

+14-14
Original file line numberDiff line numberDiff line change
@@ -400,11 +400,10 @@ static void PrintJavaScriptErrorProperties(JSONWriter* writer,
400400
!value->ToString(context).ToLocal(&value_string)) {
401401
continue;
402402
}
403-
String::Utf8Value k(isolate, key);
403+
node::Utf8Value k(isolate, key);
404404
if (!strcmp(*k, "stack") || !strcmp(*k, "message")) continue;
405-
String::Utf8Value v(isolate, value_string);
406-
writer->json_keyvalue(std::string(*k, k.length()),
407-
std::string(*v, v.length()));
405+
node::Utf8Value v(isolate, value_string);
406+
writer->json_keyvalue(k.ToStringView(), v.ToStringView());
408407
}
409408
}
410409
writer->json_objectend(); // the end of 'errorProperties'
@@ -631,27 +630,26 @@ static void PrintResourceUsage(JSONWriter* writer) {
631630
uint64_t free_memory = uv_get_free_memory();
632631
uint64_t total_memory = uv_get_total_memory();
633632

634-
writer->json_keyvalue("free_memory", std::to_string(free_memory));
635-
writer->json_keyvalue("total_memory", std::to_string(total_memory));
633+
writer->json_keyvalue("free_memory", free_memory);
634+
writer->json_keyvalue("total_memory", total_memory);
636635

637636
size_t rss;
638637
int err = uv_resident_set_memory(&rss);
639638
if (!err) {
640-
writer->json_keyvalue("rss", std::to_string(rss));
639+
writer->json_keyvalue("rss", rss);
641640
}
642641

643642
uint64_t constrained_memory = uv_get_constrained_memory();
644643
if (constrained_memory) {
645-
writer->json_keyvalue("constrained_memory",
646-
std::to_string(constrained_memory));
644+
writer->json_keyvalue("constrained_memory", constrained_memory);
647645
}
648646

649647
// See GuessMemoryAvailableToTheProcess
650648
if (!err && constrained_memory && constrained_memory >= rss) {
651649
uint64_t available_memory = constrained_memory - rss;
652-
writer->json_keyvalue("available_memory", std::to_string(available_memory));
650+
writer->json_keyvalue("available_memory", available_memory);
653651
} else {
654-
writer->json_keyvalue("available_memory", std::to_string(free_memory));
652+
writer->json_keyvalue("available_memory", free_memory);
655653
}
656654

657655
if (uv_getrusage(&rusage) == 0) {
@@ -668,7 +666,7 @@ static void PrintResourceUsage(JSONWriter* writer) {
668666
writer->json_keyvalue("cpuConsumptionPercent", cpu_percentage);
669667
writer->json_keyvalue("userCpuConsumptionPercent", user_cpu_percentage);
670668
writer->json_keyvalue("kernelCpuConsumptionPercent", kernel_cpu_percentage);
671-
writer->json_keyvalue("maxRss", std::to_string(rusage.ru_maxrss * 1024));
669+
writer->json_keyvalue("maxRss", rusage.ru_maxrss * 1024);
672670
writer->json_objectstart("pageFaults");
673671
writer->json_keyvalue("IORequired", rusage.ru_majflt);
674672
writer->json_keyvalue("IONotRequired", rusage.ru_minflt);
@@ -795,13 +793,15 @@ static void PrintComponentVersions(JSONWriter* writer) {
795793
writer->json_objectstart("componentVersions");
796794

797795
#define V(key) +1
798-
std::pair<std::string, std::string> versions_array[NODE_VERSIONS_KEYS(V)];
796+
std::pair<std::string_view, std::string_view>
797+
versions_array[NODE_VERSIONS_KEYS(V)];
799798
#undef V
800799
auto* slot = &versions_array[0];
801800

802801
#define V(key) \
803802
do { \
804-
*slot++ = std::make_pair(#key, per_process::metadata.versions.key); \
803+
*slot++ = std::pair<std::string_view, std::string_view>( \
804+
#key, per_process::metadata.versions.key); \
805805
} while (0);
806806
NODE_VERSIONS_KEYS(V)
807807
#undef V

src/node_report_utils.cc

+29-33
Original file line numberDiff line numberDiff line change
@@ -83,79 +83,75 @@ static void ReportEndpoints(uv_handle_t* h, JSONWriter* writer) {
8383
// Utility function to format libuv pipe information.
8484
static void ReportPipeEndpoints(uv_handle_t* h, JSONWriter* writer) {
8585
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
86-
MallocedBuffer<char> buffer(0);
87-
size_t buffer_size = 0;
86+
MaybeStackBuffer<char> buffer;
87+
size_t buffer_size = buffer.capacity();
8888
int rc = -1;
8989

9090
// First call to get required buffer size.
91-
rc = uv_pipe_getsockname(&handle->pipe, buffer.data, &buffer_size);
91+
rc = uv_pipe_getsockname(&handle->pipe, buffer.out(), &buffer_size);
9292
if (rc == UV_ENOBUFS) {
93-
buffer = MallocedBuffer<char>(buffer_size);
94-
if (buffer.data != nullptr) {
95-
rc = uv_pipe_getsockname(&handle->pipe, buffer.data, &buffer_size);
96-
} else {
97-
buffer_size = 0;
98-
}
93+
buffer.AllocateSufficientStorage(buffer_size);
94+
rc = uv_pipe_getsockname(&handle->pipe, buffer.out(), &buffer_size);
9995
}
100-
if (rc == 0 && buffer_size != 0 && buffer.data != nullptr) {
101-
writer->json_keyvalue("localEndpoint", buffer.data);
96+
if (rc == 0 && buffer_size != 0) {
97+
buffer.SetLength(buffer_size);
98+
writer->json_keyvalue("localEndpoint", buffer.ToStringView());
10299
} else {
103100
writer->json_keyvalue("localEndpoint", null);
104101
}
105102

106103
// First call to get required buffer size.
107-
rc = uv_pipe_getpeername(&handle->pipe, buffer.data, &buffer_size);
104+
buffer_size = buffer.capacity();
105+
rc = uv_pipe_getpeername(&handle->pipe, buffer.out(), &buffer_size);
108106
if (rc == UV_ENOBUFS) {
109-
buffer = MallocedBuffer<char>(buffer_size);
110-
if (buffer.data != nullptr) {
111-
rc = uv_pipe_getpeername(&handle->pipe, buffer.data, &buffer_size);
112-
}
107+
buffer.AllocateSufficientStorage(buffer_size);
108+
rc = uv_pipe_getpeername(&handle->pipe, buffer.out(), &buffer_size);
113109
}
114-
if (rc == 0 && buffer_size != 0 && buffer.data != nullptr) {
115-
writer->json_keyvalue("remoteEndpoint", buffer.data);
110+
if (rc == 0 && buffer_size != 0) {
111+
buffer.SetLength(buffer_size);
112+
writer->json_keyvalue("remoteEndpoint", buffer.ToStringView());
116113
} else {
117114
writer->json_keyvalue("remoteEndpoint", null);
118115
}
119116
}
120117

121118
// Utility function to format libuv path information.
122119
static void ReportPath(uv_handle_t* h, JSONWriter* writer) {
123-
MallocedBuffer<char> buffer(0);
120+
MaybeStackBuffer<char> buffer;
124121
int rc = -1;
125-
size_t size = 0;
122+
size_t size = buffer.capacity();
126123
uv_any_handle* handle = reinterpret_cast<uv_any_handle*>(h);
127-
bool wrote_filename = false;
128124
// First call to get required buffer size.
129125
switch (h->type) {
130126
case UV_FS_EVENT:
131-
rc = uv_fs_event_getpath(&(handle->fs_event), buffer.data, &size);
127+
rc = uv_fs_event_getpath(&(handle->fs_event), buffer.out(), &size);
132128
break;
133129
case UV_FS_POLL:
134-
rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.data, &size);
130+
rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.out(), &size);
135131
break;
136132
default:
137133
break;
138134
}
139135
if (rc == UV_ENOBUFS) {
140-
buffer = MallocedBuffer<char>(size + 1);
136+
buffer.AllocateSufficientStorage(size);
141137
switch (h->type) {
142138
case UV_FS_EVENT:
143-
rc = uv_fs_event_getpath(&(handle->fs_event), buffer.data, &size);
139+
rc = uv_fs_event_getpath(&(handle->fs_event), buffer.out(), &size);
144140
break;
145141
case UV_FS_POLL:
146-
rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.data, &size);
142+
rc = uv_fs_poll_getpath(&(handle->fs_poll), buffer.out(), &size);
147143
break;
148144
default:
149145
break;
150146
}
151-
if (rc == 0) {
152-
// buffer is not null terminated.
153-
buffer.data[size] = '\0';
154-
writer->json_keyvalue("filename", buffer.data);
155-
wrote_filename = true;
156-
}
157147
}
158-
if (!wrote_filename) writer->json_keyvalue("filename", null);
148+
149+
if (rc == 0 && size > 0) {
150+
buffer.SetLength(size);
151+
writer->json_keyvalue("filename", buffer.ToStringView());
152+
} else {
153+
writer->json_keyvalue("filename", null);
154+
}
159155
}
160156

161157
// Utility function to walk libuv handles.

src/util.h

+8-5
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,10 @@
3737
#include <array>
3838
#include <limits>
3939
#include <memory>
40+
#include <set>
4041
#include <string>
4142
#include <string_view>
4243
#include <type_traits>
43-
#include <set>
4444
#include <unordered_map>
4545
#include <utility>
4646
#include <vector>
@@ -473,6 +473,11 @@ class MaybeStackBuffer {
473473
free(buf_);
474474
}
475475

476+
inline std::basic_string<T> ToString() const { return {out(), length()}; }
477+
inline std::basic_string_view<T> ToStringView() const {
478+
return {out(), length()};
479+
}
480+
476481
private:
477482
size_t length_;
478483
// capacity of the malloc'ed buf_
@@ -520,8 +525,6 @@ class Utf8Value : public MaybeStackBuffer<char> {
520525
public:
521526
explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
522527

523-
inline std::string ToString() const { return std::string(out(), length()); }
524-
525528
inline bool operator==(const char* a) const {
526529
return strcmp(out(), a) == 0;
527530
}
@@ -596,7 +599,7 @@ struct MallocedBuffer {
596599
}
597600

598601
void Truncate(size_t new_size) {
599-
CHECK(new_size <= size);
602+
CHECK_LE(new_size, size);
600603
size = new_size;
601604
}
602605

@@ -605,7 +608,7 @@ struct MallocedBuffer {
605608
data = UncheckedRealloc(data, new_size);
606609
}
607610

608-
inline bool is_empty() const { return data == nullptr; }
611+
bool is_empty() const { return data == nullptr; }
609612

610613
MallocedBuffer() : data(nullptr), size(0) {}
611614
explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {}

0 commit comments

Comments
 (0)