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