1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 #ifndef SRC_UTIL_H_
23 #define SRC_UTIL_H_
24
25 #if defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
26
27 #include "v8.h"
28
29 #include "node.h"
30
31 #include <climits>
32 #include <cstddef>
33 #include <cstdio>
34 #include <cstdlib>
35 #include <cstring>
36
37 #include <array>
38 #include <limits>
39 #include <memory>
40 #include <set>
41 #include <string>
42 #include <string_view>
43 #include <type_traits>
44 #include <unordered_map>
45 #include <utility>
46 #include <vector>
47
48 #ifdef __GNUC__
49 #define MUST_USE_RESULT __attribute__((warn_unused_result))
50 #else
51 #define MUST_USE_RESULT
52 #endif
53
54 namespace node {
55
56 bool ReadSystemXpmState();
57
58 // Maybe remove kPathSeparator when cpp17 is ready
59 #ifdef _WIN32
60 constexpr char kPathSeparator = '\\';
61 /* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
62 #define PATH_MAX_BYTES (MAX_PATH * 4)
63 #else
64 constexpr char kPathSeparator = '/';
65 #define PATH_MAX_BYTES (PATH_MAX)
66 #endif
67
68 // These should be used in our code as opposed to the native
69 // versions as they abstract out some platform and or
70 // compiler version specific functionality
71 // malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
72 // that the standard allows them to either return a unique pointer or a
73 // nullptr for zero-sized allocation requests. Normalize by always using
74 // a nullptr.
75 template <typename T>
76 inline T* UncheckedRealloc(T* pointer, size_t n);
77 template <typename T>
78 inline T* UncheckedMalloc(size_t n);
79 template <typename T>
80 inline T* UncheckedCalloc(size_t n);
81
82 // Same things, but aborts immediately instead of returning nullptr when
83 // no memory is available.
84 template <typename T>
85 inline T* Realloc(T* pointer, size_t n);
86 template <typename T>
87 inline T* Malloc(size_t n);
88 template <typename T>
89 inline T* Calloc(size_t n);
90
91 inline char* Malloc(size_t n);
92 inline char* Calloc(size_t n);
93 inline char* UncheckedMalloc(size_t n);
94 inline char* UncheckedCalloc(size_t n);
95
96 template <typename T>
97 inline T MultiplyWithOverflowCheck(T a, T b);
98
99 namespace per_process {
100 // Tells whether the per-process V8::Initialize() is called and
101 // if it is safe to call v8::Isolate::TryGetCurrent().
102 extern bool v8_initialized;
103 } // namespace per_process
104
105 // Used by the allocation functions when allocation fails.
106 // Thin wrapper around v8::Isolate::LowMemoryNotification() that checks
107 // whether V8 is initialized.
108 void LowMemoryNotification();
109
110 // The reason that Assert() takes a struct argument instead of individual
111 // const char*s is to ease instruction cache pressure in calls from CHECK.
112 struct AssertionInfo {
113 const char* file_line; // filename:line
114 const char* message;
115 const char* function;
116 };
117 [[noreturn]] void NODE_EXTERN_PRIVATE Assert(const AssertionInfo& info);
118 [[noreturn]] void NODE_EXTERN_PRIVATE Abort();
119 void DumpBacktrace(FILE* fp);
120
121 // Windows 8+ does not like abort() in Release mode
122 #ifdef _WIN32
123 #define ABORT_NO_BACKTRACE() _exit(134)
124 #else
125 #define ABORT_NO_BACKTRACE() abort()
126 #endif
127
128 #define ABORT() node::Abort()
129
130 #define ERROR_AND_ABORT(expr) \
131 do { \
132 /* Make sure that this struct does not end up in inline code, but */ \
133 /* rather in a read-only data section when modifying this code. */ \
134 static const node::AssertionInfo args = { \
135 __FILE__ ":" STRINGIFY(__LINE__), #expr, PRETTY_FUNCTION_NAME \
136 }; \
137 node::Assert(args); \
138 } while (0)
139
140 #ifdef __GNUC__
141 #define LIKELY(expr) __builtin_expect(!!(expr), 1)
142 #define UNLIKELY(expr) __builtin_expect(!!(expr), 0)
143 #define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__
144 #else
145 #define LIKELY(expr) expr
146 #define UNLIKELY(expr) expr
147 #define PRETTY_FUNCTION_NAME ""
148 #endif
149
150 #define STRINGIFY_(x) #x
151 #define STRINGIFY(x) STRINGIFY_(x)
152
153 #define CHECK(expr) \
154 do { \
155 if (UNLIKELY(!(expr))) { \
156 ERROR_AND_ABORT(expr); \
157 } \
158 } while (0)
159
160 #define CHECK_EQ(a, b) CHECK((a) == (b))
161 #define CHECK_GE(a, b) CHECK((a) >= (b))
162 #define CHECK_GT(a, b) CHECK((a) > (b))
163 #define CHECK_LE(a, b) CHECK((a) <= (b))
164 #define CHECK_LT(a, b) CHECK((a) < (b))
165 #define CHECK_NE(a, b) CHECK((a) != (b))
166 #define CHECK_NULL(val) CHECK((val) == nullptr)
167 #define CHECK_NOT_NULL(val) CHECK((val) != nullptr)
168 #define CHECK_IMPLIES(a, b) CHECK(!(a) || (b))
169
170 #ifdef DEBUG
171 #define DCHECK(expr) CHECK(expr)
172 #define DCHECK_EQ(a, b) CHECK((a) == (b))
173 #define DCHECK_GE(a, b) CHECK((a) >= (b))
174 #define DCHECK_GT(a, b) CHECK((a) > (b))
175 #define DCHECK_LE(a, b) CHECK((a) <= (b))
176 #define DCHECK_LT(a, b) CHECK((a) < (b))
177 #define DCHECK_NE(a, b) CHECK((a) != (b))
178 #define DCHECK_NULL(val) CHECK((val) == nullptr)
179 #define DCHECK_NOT_NULL(val) CHECK((val) != nullptr)
180 #define DCHECK_IMPLIES(a, b) CHECK(!(a) || (b))
181 #else
182 #define DCHECK(expr)
183 #define DCHECK_EQ(a, b)
184 #define DCHECK_GE(a, b)
185 #define DCHECK_GT(a, b)
186 #define DCHECK_LE(a, b)
187 #define DCHECK_LT(a, b)
188 #define DCHECK_NE(a, b)
189 #define DCHECK_NULL(val)
190 #define DCHECK_NOT_NULL(val)
191 #define DCHECK_IMPLIES(a, b)
192 #endif
193
194
195 #define UNREACHABLE(...) \
196 ERROR_AND_ABORT("Unreachable code reached" __VA_OPT__(": ") __VA_ARGS__)
197
198 // ECMA262 20.1.2.6 Number.MAX_SAFE_INTEGER (2^53-1)
199 constexpr int64_t kMaxSafeJsInteger = 9007199254740991;
200
201 inline bool IsSafeJsInt(v8::Local<v8::Value> v);
202
203 // TAILQ-style intrusive list node.
204 template <typename T>
205 class ListNode;
206
207 // TAILQ-style intrusive list head.
208 template <typename T, ListNode<T> (T::*M)>
209 class ListHead;
210
211 template <typename T>
212 class ListNode {
213 public:
214 inline ListNode();
215 inline ~ListNode();
216 inline void Remove();
217 inline bool IsEmpty() const;
218
219 ListNode(const ListNode&) = delete;
220 ListNode& operator=(const ListNode&) = delete;
221
222 private:
223 template <typename U, ListNode<U> (U::*M)> friend class ListHead;
224 friend int GenDebugSymbols();
225 ListNode* prev_;
226 ListNode* next_;
227 };
228
229 template <typename T, ListNode<T> (T::*M)>
230 class ListHead {
231 public:
232 class Iterator {
233 public:
234 inline T* operator*() const;
235 inline const Iterator& operator++();
236 inline bool operator!=(const Iterator& that) const;
237
238 private:
239 friend class ListHead;
240 inline explicit Iterator(ListNode<T>* node);
241 ListNode<T>* node_;
242 };
243
244 inline ListHead() = default;
245 inline ~ListHead();
246 inline void PushBack(T* element);
247 inline void PushFront(T* element);
248 inline bool IsEmpty() const;
249 inline T* PopFront();
250 inline Iterator begin() const;
251 inline Iterator end() const;
252
253 ListHead(const ListHead&) = delete;
254 ListHead& operator=(const ListHead&) = delete;
255
256 private:
257 friend int GenDebugSymbols();
258 ListNode<T> head_;
259 };
260
261 // The helper is for doing safe downcasts from base types to derived types.
262 template <typename Inner, typename Outer>
263 class ContainerOfHelper {
264 public:
265 inline ContainerOfHelper(Inner Outer::*field, Inner* pointer);
266 template <typename TypeName>
267 inline operator TypeName*() const;
268 private:
269 Outer* const pointer_;
270 };
271
272 // Calculate the address of the outer (i.e. embedding) struct from
273 // the interior pointer to a data member.
274 template <typename Inner, typename Outer>
275 constexpr ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
276 Inner* pointer);
277
278 class KVStore {
279 public:
280 KVStore() = default;
281 virtual ~KVStore() = default;
282 KVStore(const KVStore&) = delete;
283 KVStore& operator=(const KVStore&) = delete;
284 KVStore(KVStore&&) = delete;
285 KVStore& operator=(KVStore&&) = delete;
286
287 virtual v8::MaybeLocal<v8::String> Get(v8::Isolate* isolate,
288 v8::Local<v8::String> key) const = 0;
289 virtual v8::Maybe<std::string> Get(const char* key) const = 0;
290 virtual void Set(v8::Isolate* isolate,
291 v8::Local<v8::String> key,
292 v8::Local<v8::String> value) = 0;
293 virtual int32_t Query(v8::Isolate* isolate,
294 v8::Local<v8::String> key) const = 0;
295 virtual int32_t Query(const char* key) const = 0;
296 virtual void Delete(v8::Isolate* isolate, v8::Local<v8::String> key) = 0;
297 virtual v8::Local<v8::Array> Enumerate(v8::Isolate* isolate) const = 0;
298
299 virtual std::shared_ptr<KVStore> Clone(v8::Isolate* isolate) const;
300 virtual v8::Maybe<bool> AssignFromObject(v8::Local<v8::Context> context,
301 v8::Local<v8::Object> entries);
302 v8::Maybe<bool> AssignToObject(v8::Isolate* isolate,
303 v8::Local<v8::Context> context,
304 v8::Local<v8::Object> object);
305
306 static std::shared_ptr<KVStore> CreateMapKVStore();
307 };
308
309 // Convenience wrapper around v8::String::NewFromOneByte().
310 inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
311 const char* data,
312 int length = -1);
313
314 // For the people that compile with -funsigned-char.
315 inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
316 const signed char* data,
317 int length = -1);
318
319 inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
320 const unsigned char* data,
321 int length = -1);
322
323 // Used to be a macro, hence the uppercase name.
324 template <int N>
FIXED_ONE_BYTE_STRING( v8::Isolate* isolate, const char(&data)[N])325 inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
326 v8::Isolate* isolate,
327 const char(&data)[N]) {
328 return OneByteString(isolate, data, N - 1);
329 }
330
331 template <std::size_t N>
FIXED_ONE_BYTE_STRING( v8::Isolate* isolate, const std::array<char, N>& arr)332 inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
333 v8::Isolate* isolate,
334 const std::array<char, N>& arr) {
335 return OneByteString(isolate, arr.data(), N - 1);
336 }
337
338
339
340 // Swaps bytes in place. nbytes is the number of bytes to swap and must be a
341 // multiple of the word size (checked by function).
342 inline void SwapBytes16(char* data, size_t nbytes);
343 inline void SwapBytes32(char* data, size_t nbytes);
344 inline void SwapBytes64(char* data, size_t nbytes);
345
346 // tolower() is locale-sensitive. Use ToLower() instead.
347 inline char ToLower(char c);
348 inline std::string ToLower(const std::string& in);
349
350 // toupper() is locale-sensitive. Use ToUpper() instead.
351 inline char ToUpper(char c);
352 inline std::string ToUpper(const std::string& in);
353
354 // strcasecmp() is locale-sensitive. Use StringEqualNoCase() instead.
355 inline bool StringEqualNoCase(const char* a, const char* b);
356
357 // strncasecmp() is locale-sensitive. Use StringEqualNoCaseN() instead.
358 inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length);
359
360 template <typename T, size_t N>
361 constexpr size_t arraysize(const T (&)[N]) {
362 return N;
363 }
364
365 template <typename T, size_t N>
366 constexpr size_t strsize(const T (&)[N]) {
367 return N - 1;
368 }
369
370 // Allocates an array of member type T. For up to kStackStorageSize items,
371 // the stack is used, otherwise malloc().
372 template <typename T, size_t kStackStorageSize = 1024>
373 class MaybeStackBuffer {
374 public:
out() const375 const T* out() const {
376 return buf_;
377 }
378
out()379 T* out() {
380 return buf_;
381 }
382
383 // operator* for compatibility with `v8::String::(Utf8)Value`
operator *()384 T* operator*() {
385 return buf_;
386 }
387
operator *() const388 const T* operator*() const {
389 return buf_;
390 }
391
operator [](size_t index)392 T& operator[](size_t index) {
393 CHECK_LT(index, length());
394 return buf_[index];
395 }
396
operator [](size_t index) const397 const T& operator[](size_t index) const {
398 CHECK_LT(index, length());
399 return buf_[index];
400 }
401
length() const402 size_t length() const {
403 return length_;
404 }
405
406 // Current maximum capacity of the buffer with which SetLength() can be used
407 // without first calling AllocateSufficientStorage().
capacity() const408 size_t capacity() const {
409 return capacity_;
410 }
411
412 // Make sure enough space for `storage` entries is available.
413 // This method can be called multiple times throughout the lifetime of the
414 // buffer, but once this has been called Invalidate() cannot be used.
415 // Content of the buffer in the range [0, length()) is preserved.
416 void AllocateSufficientStorage(size_t storage);
417
SetLength(size_t length)418 void SetLength(size_t length) {
419 // capacity() returns how much memory is actually available.
420 CHECK_LE(length, capacity());
421 length_ = length;
422 }
423
SetLengthAndZeroTerminate(size_t length)424 void SetLengthAndZeroTerminate(size_t length) {
425 // capacity() returns how much memory is actually available.
426 CHECK_LE(length + 1, capacity());
427 SetLength(length);
428
429 // T() is 0 for integer types, nullptr for pointers, etc.
430 buf_[length] = T();
431 }
432
433 // Make dereferencing this object return nullptr.
434 // This method can be called multiple times throughout the lifetime of the
435 // buffer, but once this has been called AllocateSufficientStorage() cannot
436 // be used.
Invalidate()437 void Invalidate() {
438 CHECK(!IsAllocated());
439 capacity_ = 0;
440 length_ = 0;
441 buf_ = nullptr;
442 }
443
444 // If the buffer is stored in the heap rather than on the stack.
IsAllocated() const445 bool IsAllocated() const {
446 return !IsInvalidated() && buf_ != buf_st_;
447 }
448
449 // If Invalidate() has been called.
IsInvalidated() const450 bool IsInvalidated() const {
451 return buf_ == nullptr;
452 }
453
454 // Release ownership of the malloc'd buffer.
455 // Note: This does not free the buffer.
Release()456 void Release() {
457 CHECK(IsAllocated());
458 buf_ = buf_st_;
459 length_ = 0;
460 capacity_ = arraysize(buf_st_);
461 }
462
MaybeStackBuffer()463 MaybeStackBuffer()
464 : length_(0), capacity_(arraysize(buf_st_)), buf_(buf_st_) {
465 // Default to a zero-length, null-terminated buffer.
466 buf_[0] = T();
467 }
468
MaybeStackBuffer(size_t storage)469 explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() {
470 AllocateSufficientStorage(storage);
471 }
472
~MaybeStackBuffer()473 ~MaybeStackBuffer() {
474 if (IsAllocated())
475 free(buf_);
476 }
477
ToString() const478 inline std::basic_string<T> ToString() const { return {out(), length()}; }
ToStringView() const479 inline std::basic_string_view<T> ToStringView() const {
480 return {out(), length()};
481 }
482
483 private:
484 size_t length_;
485 // capacity of the malloc'ed buf_
486 size_t capacity_;
487 T* buf_;
488 T buf_st_[kStackStorageSize];
489 };
490
491 // Provides access to an ArrayBufferView's storage, either the original,
492 // or for small data, a copy of it. This object's lifetime is bound to the
493 // original ArrayBufferView's lifetime.
494 template <typename T, size_t kStackStorageSize = 64>
495 class ArrayBufferViewContents {
496 public:
497 ArrayBufferViewContents() = default;
498
499 ArrayBufferViewContents(const ArrayBufferViewContents&) = delete;
500 void operator=(const ArrayBufferViewContents&) = delete;
501
502 explicit inline ArrayBufferViewContents(v8::Local<v8::Value> value);
503 explicit inline ArrayBufferViewContents(v8::Local<v8::Object> value);
504 explicit inline ArrayBufferViewContents(v8::Local<v8::ArrayBufferView> abv);
505 inline void Read(v8::Local<v8::ArrayBufferView> abv);
506 inline void ReadValue(v8::Local<v8::Value> buf);
507
WasDetached() const508 inline bool WasDetached() const { return was_detached_; }
data() const509 inline const T* data() const { return data_; }
length() const510 inline size_t length() const { return length_; }
511
512 private:
513 // Declaring operator new and delete as deleted is not spec compliant.
514 // Therefore, declare them private instead to disable dynamic alloc.
515 void* operator new(size_t size);
516 void* operator new[](size_t size);
517 void operator delete(void*, size_t);
518 void operator delete[](void*, size_t);
519
520 T stack_storage_[kStackStorageSize];
521 T* data_ = nullptr;
522 size_t length_ = 0;
523 bool was_detached_ = false;
524 };
525
526 class Utf8Value : public MaybeStackBuffer<char> {
527 public:
528 explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
529
operator ==(const char* a) const530 inline bool operator==(const char* a) const { return strcmp(out(), a) == 0; }
operator !=(const char* a) const531 inline bool operator!=(const char* a) const { return !(*this == a); }
532 };
533
534 class TwoByteValue : public MaybeStackBuffer<uint16_t> {
535 public:
536 explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
537 };
538
539 class BufferValue : public MaybeStackBuffer<char> {
540 public:
541 explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
542
ToString() const543 inline std::string ToString() const { return std::string(out(), length()); }
544 };
545
546 #define SPREAD_BUFFER_ARG(val, name) \
547 CHECK((val)->IsArrayBufferView()); \
548 v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>(); \
549 const size_t name##_offset = name->ByteOffset(); \
550 const size_t name##_length = name->ByteLength(); \
551 char* const name##_data = \
552 static_cast<char*>(name->Buffer()->Data()) + name##_offset; \
553 if (name##_length > 0) CHECK_NE(name##_data, nullptr);
554
555 // Use this when a variable or parameter is unused in order to explicitly
556 // silence a compiler warning about that.
USE(T&&)557 template <typename T> inline void USE(T&&) {}
558
559 template <typename Fn>
560 struct OnScopeLeaveImpl {
561 Fn fn_;
562 bool active_;
563
OnScopeLeaveImplnode::OnScopeLeaveImpl564 explicit OnScopeLeaveImpl(Fn&& fn) : fn_(std::move(fn)), active_(true) {}
~OnScopeLeaveImplnode::OnScopeLeaveImpl565 ~OnScopeLeaveImpl() { if (active_) fn_(); }
566
567 OnScopeLeaveImpl(const OnScopeLeaveImpl& other) = delete;
568 OnScopeLeaveImpl& operator=(const OnScopeLeaveImpl& other) = delete;
OnScopeLeaveImplnode::OnScopeLeaveImpl569 OnScopeLeaveImpl(OnScopeLeaveImpl&& other)
570 : fn_(std::move(other.fn_)), active_(other.active_) {
571 other.active_ = false;
572 }
573 };
574
575 // Run a function when exiting the current scope. Used like this:
576 // auto on_scope_leave = OnScopeLeave([&] {
577 // // ... run some code ...
578 // });
579 template <typename Fn>
OnScopeLeave(Fn&& fn)580 inline MUST_USE_RESULT OnScopeLeaveImpl<Fn> OnScopeLeave(Fn&& fn) {
581 return OnScopeLeaveImpl<Fn>{std::move(fn)};
582 }
583
584 // Simple RAII wrapper for contiguous data that uses malloc()/free().
585 template <typename T>
586 struct MallocedBuffer {
587 T* data;
588 size_t size;
589
releasenode::MallocedBuffer590 T* release() {
591 T* ret = data;
592 data = nullptr;
593 return ret;
594 }
595
Truncatenode::MallocedBuffer596 void Truncate(size_t new_size) {
597 CHECK_LE(new_size, size);
598 size = new_size;
599 }
600
Reallocnode::MallocedBuffer601 void Realloc(size_t new_size) {
602 Truncate(new_size);
603 data = UncheckedRealloc(data, new_size);
604 }
605
is_emptynode::MallocedBuffer606 bool is_empty() const { return data == nullptr; }
607
MallocedBuffernode::MallocedBuffer608 MallocedBuffer() : data(nullptr), size(0) {}
MallocedBuffernode::MallocedBuffer609 explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {}
MallocedBuffernode::MallocedBuffer610 MallocedBuffer(T* data, size_t size) : data(data), size(size) {}
MallocedBuffernode::MallocedBuffer611 MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) {
612 other.data = nullptr;
613 }
operator =node::MallocedBuffer614 MallocedBuffer& operator=(MallocedBuffer&& other) {
615 this->~MallocedBuffer();
616 return *new(this) MallocedBuffer(std::move(other));
617 }
~MallocedBuffernode::MallocedBuffer618 ~MallocedBuffer() {
619 free(data);
620 }
621 MallocedBuffer(const MallocedBuffer&) = delete;
622 MallocedBuffer& operator=(const MallocedBuffer&) = delete;
623 };
624
625 template <typename T>
626 class NonCopyableMaybe {
627 public:
NonCopyableMaybe()628 NonCopyableMaybe() : empty_(true) {}
NonCopyableMaybe(T&& value)629 explicit NonCopyableMaybe(T&& value)
630 : empty_(false),
631 value_(std::move(value)) {}
632
IsEmpty() const633 bool IsEmpty() const {
634 return empty_;
635 }
636
get() const637 const T* get() const {
638 return empty_ ? nullptr : &value_;
639 }
640
operator ->() const641 const T* operator->() const {
642 CHECK(!empty_);
643 return &value_;
644 }
645
Release()646 T&& Release() {
647 CHECK_EQ(empty_, false);
648 empty_ = true;
649 return std::move(value_);
650 }
651
652 private:
653 bool empty_;
654 T value_;
655 };
656
657 // Test whether some value can be called with ().
658 template <typename T, typename = void>
659 struct is_callable : std::is_function<T> { };
660
661 template <typename T>
662 struct is_callable<T, typename std::enable_if<
663 std::is_same<decltype(void(&T::operator())), void>::value
664 >::type> : std::true_type { };
665
666 template <typename T, void (*function)(T*)>
667 struct FunctionDeleter {
operator ()node::FunctionDeleter668 void operator()(T* pointer) const { function(pointer); }
669 typedef std::unique_ptr<T, FunctionDeleter> Pointer;
670 };
671
672 template <typename T, void (*function)(T*)>
673 using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
674
675 std::vector<std::string_view> SplitString(const std::string_view in,
676 const std::string_view delim);
677
678 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
679 std::string_view str,
680 v8::Isolate* isolate = nullptr);
681 template <typename T, typename test_for_number =
682 typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
683 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
684 const T& number,
685 v8::Isolate* isolate = nullptr);
686 template <typename T>
687 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
688 const std::vector<T>& vec,
689 v8::Isolate* isolate = nullptr);
690 template <typename T>
691 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
692 const std::set<T>& set,
693 v8::Isolate* isolate = nullptr);
694 template <typename T, typename U>
695 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
696 const std::unordered_map<T, U>& map,
697 v8::Isolate* isolate = nullptr);
698
699 // These macros expects a `Isolate* isolate` and a `Local<Context> context`
700 // to be in the scope.
701 #define READONLY_PROPERTY(obj, name, value) \
702 do { \
703 obj->DefineOwnProperty( \
704 context, FIXED_ONE_BYTE_STRING(isolate, name), value, v8::ReadOnly) \
705 .Check(); \
706 } while (0)
707
708 #define READONLY_DONT_ENUM_PROPERTY(obj, name, var) \
709 do { \
710 obj->DefineOwnProperty( \
711 context, \
712 OneByteString(isolate, name), \
713 var, \
714 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum)) \
715 .Check(); \
716 } while (0)
717
718 #define READONLY_FALSE_PROPERTY(obj, name) \
719 READONLY_PROPERTY(obj, name, v8::False(isolate))
720
721 #define READONLY_TRUE_PROPERTY(obj, name) \
722 READONLY_PROPERTY(obj, name, v8::True(isolate))
723
724 #define READONLY_STRING_PROPERTY(obj, name, str) \
725 READONLY_PROPERTY(obj, name, ToV8Value(context, str).ToLocalChecked())
726
727 // Variation on NODE_DEFINE_CONSTANT that sets a String value.
728 #define NODE_DEFINE_STRING_CONSTANT(target, name, constant) \
729 do { \
730 v8::Isolate* isolate = target->GetIsolate(); \
731 v8::Local<v8::String> constant_name = \
732 v8::String::NewFromUtf8(isolate, name).ToLocalChecked(); \
733 v8::Local<v8::String> constant_value = \
734 v8::String::NewFromUtf8(isolate, constant).ToLocalChecked(); \
735 v8::PropertyAttribute constant_attributes = \
736 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); \
737 target \
738 ->DefineOwnProperty(isolate->GetCurrentContext(), \
739 constant_name, \
740 constant_value, \
741 constant_attributes) \
742 .Check(); \
743 } while (0)
744
745 enum class Endianness { LITTLE, BIG };
746
GetEndianness()747 inline Endianness GetEndianness() {
748 // Constant-folded by the compiler.
749 const union {
750 uint8_t u8[2];
751 uint16_t u16;
752 } u = {{1, 0}};
753 return u.u16 == 1 ? Endianness::LITTLE : Endianness::BIG;
754 }
755
IsLittleEndian()756 inline bool IsLittleEndian() {
757 return GetEndianness() == Endianness::LITTLE;
758 }
759
IsBigEndian()760 inline bool IsBigEndian() {
761 return GetEndianness() == Endianness::BIG;
762 }
763
764 // Round up a to the next highest multiple of b.
765 template <typename T>
RoundUp(T a, T b)766 constexpr T RoundUp(T a, T b) {
767 return a % b != 0 ? a + b - (a % b) : a;
768 }
769
770 // Align ptr to an `alignment`-bytes boundary.
771 template <typename T, typename U>
AlignUp(T* ptr, U alignment)772 constexpr T* AlignUp(T* ptr, U alignment) {
773 return reinterpret_cast<T*>(
774 RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment));
775 }
776
777 class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> {
778 public:
779 inline explicit SlicedArguments(
780 const v8::FunctionCallbackInfo<v8::Value>& args, size_t start = 0);
781 };
782
783 // Convert a v8::PersistentBase, e.g. v8::Global, to a Local, with an extra
784 // optimization for strong persistent handles.
785 class PersistentToLocal {
786 public:
787 // If persistent.IsWeak() == false, then do not call persistent.Reset()
788 // while the returned Local<T> is still in scope, it will destroy the
789 // reference to the object.
790 template <class TypeName>
Default( v8::Isolate* isolate, const v8::PersistentBase<TypeName>& persistent)791 static inline v8::Local<TypeName> Default(
792 v8::Isolate* isolate,
793 const v8::PersistentBase<TypeName>& persistent) {
794 if (persistent.IsWeak()) {
795 return PersistentToLocal::Weak(isolate, persistent);
796 } else {
797 return PersistentToLocal::Strong(persistent);
798 }
799 }
800
801 // Unchecked conversion from a non-weak Persistent<T> to Local<T>,
802 // use with care!
803 //
804 // Do not call persistent.Reset() while the returned Local<T> is still in
805 // scope, it will destroy the reference to the object.
806 template <class TypeName>
Strong( const v8::PersistentBase<TypeName>& persistent)807 static inline v8::Local<TypeName> Strong(
808 const v8::PersistentBase<TypeName>& persistent) {
809 DCHECK(!persistent.IsWeak());
810 return *reinterpret_cast<v8::Local<TypeName>*>(
811 const_cast<v8::PersistentBase<TypeName>*>(&persistent));
812 }
813
814 template <class TypeName>
Weak( v8::Isolate* isolate, const v8::PersistentBase<TypeName>& persistent)815 static inline v8::Local<TypeName> Weak(
816 v8::Isolate* isolate,
817 const v8::PersistentBase<TypeName>& persistent) {
818 return v8::Local<TypeName>::New(isolate, persistent);
819 }
820 };
821
822 // Can be used as a key for std::unordered_map when lookup performance is more
823 // important than size and the keys are statically used to avoid redundant hash
824 // computations.
825 class FastStringKey {
826 public:
827 constexpr explicit FastStringKey(std::string_view name);
828
829 struct Hash {
830 constexpr size_t operator()(const FastStringKey& key) const;
831 };
832 constexpr bool operator==(const FastStringKey& other) const;
833
834 constexpr std::string_view as_string_view() const;
835
836 private:
837 static constexpr size_t HashImpl(std::string_view str);
838
839 const std::string_view name_;
840 const size_t cached_hash_;
841 };
842
843 // Like std::static_pointer_cast but for unique_ptr with the default deleter.
844 template <typename T, typename U>
static_unique_pointer_cast(std::unique_ptr<U>&& ptr)845 std::unique_ptr<T> static_unique_pointer_cast(std::unique_ptr<U>&& ptr) {
846 return std::unique_ptr<T>(static_cast<T*>(ptr.release()));
847 }
848
849 #define MAYBE_FIELD_PTR(ptr, field) ptr == nullptr ? nullptr : &(ptr->field)
850
851 // Returns a non-zero code if it fails to open or read the file,
852 // aborts if it fails to close the file.
853 int ReadFileSync(std::string* result, const char* path);
854
855 v8::Local<v8::FunctionTemplate> NewFunctionTemplate(
856 v8::Isolate* isolate,
857 v8::FunctionCallback callback,
858 v8::Local<v8::Signature> signature = v8::Local<v8::Signature>(),
859 v8::ConstructorBehavior behavior = v8::ConstructorBehavior::kAllow,
860 v8::SideEffectType side_effect = v8::SideEffectType::kHasSideEffect,
861 const v8::CFunction* c_function = nullptr);
862
863 // Convenience methods for NewFunctionTemplate().
864 void SetMethod(v8::Local<v8::Context> context,
865 v8::Local<v8::Object> that,
866 const char* name,
867 v8::FunctionCallback callback);
868 // Similar to SetProtoMethod but without receiver signature checks.
869 void SetMethod(v8::Isolate* isolate,
870 v8::Local<v8::Template> that,
871 const char* name,
872 v8::FunctionCallback callback);
873
874 void SetFastMethod(v8::Local<v8::Context> context,
875 v8::Local<v8::Object> that,
876 const char* name,
877 v8::FunctionCallback slow_callback,
878 const v8::CFunction* c_function);
879 void SetFastMethodNoSideEffect(v8::Local<v8::Context> context,
880 v8::Local<v8::Object> that,
881 const char* name,
882 v8::FunctionCallback slow_callback,
883 const v8::CFunction* c_function);
884
885 void SetProtoMethod(v8::Isolate* isolate,
886 v8::Local<v8::FunctionTemplate> that,
887 const char* name,
888 v8::FunctionCallback callback);
889
890 void SetInstanceMethod(v8::Isolate* isolate,
891 v8::Local<v8::FunctionTemplate> that,
892 const char* name,
893 v8::FunctionCallback callback);
894
895 // Safe variants denote the function has no side effects.
896 void SetMethodNoSideEffect(v8::Local<v8::Context> context,
897 v8::Local<v8::Object> that,
898 const char* name,
899 v8::FunctionCallback callback);
900 void SetProtoMethodNoSideEffect(v8::Isolate* isolate,
901 v8::Local<v8::FunctionTemplate> that,
902 const char* name,
903 v8::FunctionCallback callback);
904
905 enum class SetConstructorFunctionFlag {
906 NONE,
907 SET_CLASS_NAME,
908 };
909
910 void SetConstructorFunction(v8::Local<v8::Context> context,
911 v8::Local<v8::Object> that,
912 const char* name,
913 v8::Local<v8::FunctionTemplate> tmpl,
914 SetConstructorFunctionFlag flag =
915 SetConstructorFunctionFlag::SET_CLASS_NAME);
916
917 void SetConstructorFunction(v8::Local<v8::Context> context,
918 v8::Local<v8::Object> that,
919 v8::Local<v8::String> name,
920 v8::Local<v8::FunctionTemplate> tmpl,
921 SetConstructorFunctionFlag flag =
922 SetConstructorFunctionFlag::SET_CLASS_NAME);
923
924 } // namespace node
925
926 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
927
928 #endif // SRC_UTIL_H_
929