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 #if (__GNUC__ >= 8) && !defined(__clang__)
28 #pragma GCC diagnostic push
29 #pragma GCC diagnostic ignored "-Wcast-function-type"
30 #endif
31 #include "v8.h"
32 #if (__GNUC__ >= 8) && !defined(__clang__)
33 #pragma GCC diagnostic pop
34 #endif
35
36 #include <climits>
37 #include <cstddef>
38 #include <cstdio>
39 #include <cstdlib>
40 #include <cstring>
41
42 #include <functional> // std::function
43 #include <limits>
44 #include <set>
45 #include <string>
46 #include <array>
47 #include <unordered_map>
48 #include <utility>
49
50 #ifdef __GNUC__
51 #define MUST_USE_RESULT __attribute__((warn_unused_result))
52 #else
53 #define MUST_USE_RESULT
54 #endif
55
56 namespace node {
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::GetCurrent().
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 Assert(const AssertionInfo& info);
118 [[noreturn]] void 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 // Convenience wrapper around v8::String::NewFromOneByte().
279 inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
280 const char* data,
281 int length = -1);
282
283 // For the people that compile with -funsigned-char.
284 inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
285 const signed char* data,
286 int length = -1);
287
288 inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
289 const unsigned char* data,
290 int length = -1);
291
292 // Used to be a macro, hence the uppercase name.
293 template <int N>
FIXED_ONE_BYTE_STRING(v8::Isolate * isolate,const char (& data)[N])294 inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
295 v8::Isolate* isolate,
296 const char(&data)[N]) {
297 return OneByteString(isolate, data, N - 1);
298 }
299
300 template <std::size_t N>
FIXED_ONE_BYTE_STRING(v8::Isolate * isolate,const std::array<char,N> & arr)301 inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
302 v8::Isolate* isolate,
303 const std::array<char, N>& arr) {
304 return OneByteString(isolate, arr.data(), N - 1);
305 }
306
307
308
309 // Swaps bytes in place. nbytes is the number of bytes to swap and must be a
310 // multiple of the word size (checked by function).
311 inline void SwapBytes16(char* data, size_t nbytes);
312 inline void SwapBytes32(char* data, size_t nbytes);
313 inline void SwapBytes64(char* data, size_t nbytes);
314
315 // tolower() is locale-sensitive. Use ToLower() instead.
316 inline char ToLower(char c);
317 inline std::string ToLower(const std::string& in);
318
319 // toupper() is locale-sensitive. Use ToUpper() instead.
320 inline char ToUpper(char c);
321 inline std::string ToUpper(const std::string& in);
322
323 // strcasecmp() is locale-sensitive. Use StringEqualNoCase() instead.
324 inline bool StringEqualNoCase(const char* a, const char* b);
325
326 // strncasecmp() is locale-sensitive. Use StringEqualNoCaseN() instead.
327 inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length);
328
329 template <typename T, size_t N>
arraysize(const T (&)[N])330 constexpr size_t arraysize(const T (&)[N]) {
331 return N;
332 }
333
334 // Allocates an array of member type T. For up to kStackStorageSize items,
335 // the stack is used, otherwise malloc().
336 template <typename T, size_t kStackStorageSize = 1024>
337 class MaybeStackBuffer {
338 public:
out()339 const T* out() const {
340 return buf_;
341 }
342
out()343 T* out() {
344 return buf_;
345 }
346
347 // operator* for compatibility with `v8::String::(Utf8)Value`
348 T* operator*() {
349 return buf_;
350 }
351
352 const T* operator*() const {
353 return buf_;
354 }
355
356 T& operator[](size_t index) {
357 CHECK_LT(index, length());
358 return buf_[index];
359 }
360
361 const T& operator[](size_t index) const {
362 CHECK_LT(index, length());
363 return buf_[index];
364 }
365
length()366 size_t length() const {
367 return length_;
368 }
369
370 // Current maximum capacity of the buffer with which SetLength() can be used
371 // without first calling AllocateSufficientStorage().
capacity()372 size_t capacity() const {
373 return capacity_;
374 }
375
376 // Make sure enough space for `storage` entries is available.
377 // This method can be called multiple times throughout the lifetime of the
378 // buffer, but once this has been called Invalidate() cannot be used.
379 // Content of the buffer in the range [0, length()) is preserved.
AllocateSufficientStorage(size_t storage)380 void AllocateSufficientStorage(size_t storage) {
381 CHECK(!IsInvalidated());
382 if (storage > capacity()) {
383 bool was_allocated = IsAllocated();
384 T* allocated_ptr = was_allocated ? buf_ : nullptr;
385 buf_ = Realloc(allocated_ptr, storage);
386 capacity_ = storage;
387 if (!was_allocated && length_ > 0)
388 memcpy(buf_, buf_st_, length_ * sizeof(buf_[0]));
389 }
390
391 length_ = storage;
392 }
393
SetLength(size_t length)394 void SetLength(size_t length) {
395 // capacity() returns how much memory is actually available.
396 CHECK_LE(length, capacity());
397 length_ = length;
398 }
399
SetLengthAndZeroTerminate(size_t length)400 void SetLengthAndZeroTerminate(size_t length) {
401 // capacity() returns how much memory is actually available.
402 CHECK_LE(length + 1, capacity());
403 SetLength(length);
404
405 // T() is 0 for integer types, nullptr for pointers, etc.
406 buf_[length] = T();
407 }
408
409 // Make dereferencing this object return nullptr.
410 // This method can be called multiple times throughout the lifetime of the
411 // buffer, but once this has been called AllocateSufficientStorage() cannot
412 // be used.
Invalidate()413 void Invalidate() {
414 CHECK(!IsAllocated());
415 capacity_ = 0;
416 length_ = 0;
417 buf_ = nullptr;
418 }
419
420 // If the buffer is stored in the heap rather than on the stack.
IsAllocated()421 bool IsAllocated() const {
422 return !IsInvalidated() && buf_ != buf_st_;
423 }
424
425 // If Invalidate() has been called.
IsInvalidated()426 bool IsInvalidated() const {
427 return buf_ == nullptr;
428 }
429
430 // Release ownership of the malloc'd buffer.
431 // Note: This does not free the buffer.
Release()432 void Release() {
433 CHECK(IsAllocated());
434 buf_ = buf_st_;
435 length_ = 0;
436 capacity_ = arraysize(buf_st_);
437 }
438
MaybeStackBuffer()439 MaybeStackBuffer()
440 : length_(0), capacity_(arraysize(buf_st_)), buf_(buf_st_) {
441 // Default to a zero-length, null-terminated buffer.
442 buf_[0] = T();
443 }
444
MaybeStackBuffer(size_t storage)445 explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() {
446 AllocateSufficientStorage(storage);
447 }
448
~MaybeStackBuffer()449 ~MaybeStackBuffer() {
450 if (IsAllocated())
451 free(buf_);
452 }
453
454 private:
455 size_t length_;
456 // capacity of the malloc'ed buf_
457 size_t capacity_;
458 T* buf_;
459 T buf_st_[kStackStorageSize];
460 };
461
462 // Provides access to an ArrayBufferView's storage, either the original,
463 // or for small data, a copy of it. This object's lifetime is bound to the
464 // original ArrayBufferView's lifetime.
465 template <typename T, size_t kStackStorageSize = 64>
466 class ArrayBufferViewContents {
467 public:
468 ArrayBufferViewContents() = default;
469
470 explicit inline ArrayBufferViewContents(v8::Local<v8::Value> value);
471 explicit inline ArrayBufferViewContents(v8::Local<v8::Object> value);
472 explicit inline ArrayBufferViewContents(v8::Local<v8::ArrayBufferView> abv);
473 inline void Read(v8::Local<v8::ArrayBufferView> abv);
474
data()475 inline const T* data() const { return data_; }
length()476 inline size_t length() const { return length_; }
477
478 private:
479 T stack_storage_[kStackStorageSize];
480 T* data_ = nullptr;
481 size_t length_ = 0;
482 };
483
484 class Utf8Value : public MaybeStackBuffer<char> {
485 public:
486 explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
487
ToString()488 inline std::string ToString() const { return std::string(out(), length()); }
489
490 inline bool operator==(const char* a) const {
491 return strcmp(out(), a) == 0;
492 }
493 };
494
495 class TwoByteValue : public MaybeStackBuffer<uint16_t> {
496 public:
497 explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
498 };
499
500 class BufferValue : public MaybeStackBuffer<char> {
501 public:
502 explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
503
ToString()504 inline std::string ToString() const { return std::string(out(), length()); }
505 };
506
507 #define SPREAD_BUFFER_ARG(val, name) \
508 CHECK((val)->IsArrayBufferView()); \
509 v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>(); \
510 std::shared_ptr<v8::BackingStore> name##_bs = \
511 name->Buffer()->GetBackingStore(); \
512 const size_t name##_offset = name->ByteOffset(); \
513 const size_t name##_length = name->ByteLength(); \
514 char* const name##_data = \
515 static_cast<char*>(name##_bs->Data()) + name##_offset; \
516 if (name##_length > 0) \
517 CHECK_NE(name##_data, nullptr);
518
519 // Use this when a variable or parameter is unused in order to explicitly
520 // silence a compiler warning about that.
USE(T &&)521 template <typename T> inline void USE(T&&) {}
522
523 template <typename Fn>
524 struct OnScopeLeaveImpl {
525 Fn fn_;
526 bool active_;
527
OnScopeLeaveImplOnScopeLeaveImpl528 explicit OnScopeLeaveImpl(Fn&& fn) : fn_(std::move(fn)), active_(true) {}
~OnScopeLeaveImplOnScopeLeaveImpl529 ~OnScopeLeaveImpl() { if (active_) fn_(); }
530
531 OnScopeLeaveImpl(const OnScopeLeaveImpl& other) = delete;
532 OnScopeLeaveImpl& operator=(const OnScopeLeaveImpl& other) = delete;
OnScopeLeaveImplOnScopeLeaveImpl533 OnScopeLeaveImpl(OnScopeLeaveImpl&& other)
534 : fn_(std::move(other.fn_)), active_(other.active_) {
535 other.active_ = false;
536 }
537 OnScopeLeaveImpl& operator=(OnScopeLeaveImpl&& other) {
538 if (this == &other) return *this;
539 this->~OnScopeLeave();
540 new (this)OnScopeLeaveImpl(std::move(other));
541 return *this;
542 }
543 };
544
545 // Run a function when exiting the current scope. Used like this:
546 // auto on_scope_leave = OnScopeLeave([&] {
547 // // ... run some code ...
548 // });
549 template <typename Fn>
OnScopeLeave(Fn && fn)550 inline MUST_USE_RESULT OnScopeLeaveImpl<Fn> OnScopeLeave(Fn&& fn) {
551 return OnScopeLeaveImpl<Fn>{std::move(fn)};
552 }
553
554 // Simple RAII wrapper for contiguous data that uses malloc()/free().
555 template <typename T>
556 struct MallocedBuffer {
557 T* data;
558 size_t size;
559
releaseMallocedBuffer560 T* release() {
561 T* ret = data;
562 data = nullptr;
563 return ret;
564 }
565
TruncateMallocedBuffer566 void Truncate(size_t new_size) {
567 CHECK(new_size <= size);
568 size = new_size;
569 }
570
is_emptyMallocedBuffer571 inline bool is_empty() const { return data == nullptr; }
572
MallocedBufferMallocedBuffer573 MallocedBuffer() : data(nullptr), size(0) {}
MallocedBufferMallocedBuffer574 explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {}
MallocedBufferMallocedBuffer575 MallocedBuffer(T* data, size_t size) : data(data), size(size) {}
MallocedBufferMallocedBuffer576 MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) {
577 other.data = nullptr;
578 }
579 MallocedBuffer& operator=(MallocedBuffer&& other) {
580 this->~MallocedBuffer();
581 return *new(this) MallocedBuffer(std::move(other));
582 }
~MallocedBufferMallocedBuffer583 ~MallocedBuffer() {
584 free(data);
585 }
586 MallocedBuffer(const MallocedBuffer&) = delete;
587 MallocedBuffer& operator=(const MallocedBuffer&) = delete;
588 };
589
590 template <typename T>
591 class NonCopyableMaybe {
592 public:
NonCopyableMaybe()593 NonCopyableMaybe() : empty_(true) {}
NonCopyableMaybe(T && value)594 explicit NonCopyableMaybe(T&& value)
595 : empty_(false),
596 value_(std::move(value)) {}
597
IsEmpty()598 bool IsEmpty() const {
599 return empty_;
600 }
601
Release()602 T&& Release() {
603 CHECK_EQ(empty_, false);
604 empty_ = true;
605 return std::move(value_);
606 }
607
608 private:
609 bool empty_;
610 T value_;
611 };
612
613 // Test whether some value can be called with ().
614 template <typename T, typename = void>
615 struct is_callable : std::is_function<T> { };
616
617 template <typename T>
618 struct is_callable<T, typename std::enable_if<
619 std::is_same<decltype(void(&T::operator())), void>::value
620 >::type> : std::true_type { };
621
622 template <typename T, void (*function)(T*)>
623 struct FunctionDeleter {
624 void operator()(T* pointer) const { function(pointer); }
625 typedef std::unique_ptr<T, FunctionDeleter> Pointer;
626 };
627
628 template <typename T, void (*function)(T*)>
629 using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
630
631 std::vector<std::string> SplitString(const std::string& in, char delim);
632
633 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
634 const std::string& str,
635 v8::Isolate* isolate = nullptr);
636 template <typename T, typename test_for_number =
637 typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
638 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
639 const T& number,
640 v8::Isolate* isolate = nullptr);
641 template <typename T>
642 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
643 const std::vector<T>& vec,
644 v8::Isolate* isolate = nullptr);
645 template <typename T, typename U>
646 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
647 const std::unordered_map<T, U>& map,
648 v8::Isolate* isolate = nullptr);
649
650 // These macros expects a `Isolate* isolate` and a `Local<Context> context`
651 // to be in the scope.
652 #define READONLY_PROPERTY(obj, name, value) \
653 do { \
654 obj->DefineOwnProperty( \
655 context, FIXED_ONE_BYTE_STRING(isolate, name), value, v8::ReadOnly) \
656 .Check(); \
657 } while (0)
658
659 #define READONLY_DONT_ENUM_PROPERTY(obj, name, var) \
660 do { \
661 obj->DefineOwnProperty( \
662 context, \
663 OneByteString(isolate, name), \
664 var, \
665 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum)) \
666 .Check(); \
667 } while (0)
668
669 #define READONLY_FALSE_PROPERTY(obj, name) \
670 READONLY_PROPERTY(obj, name, v8::False(isolate))
671
672 #define READONLY_TRUE_PROPERTY(obj, name) \
673 READONLY_PROPERTY(obj, name, v8::True(isolate))
674
675 #define READONLY_STRING_PROPERTY(obj, name, str) \
676 READONLY_PROPERTY(obj, name, ToV8Value(context, str).ToLocalChecked())
677
678 // Variation on NODE_DEFINE_CONSTANT that sets a String value.
679 #define NODE_DEFINE_STRING_CONSTANT(target, name, constant) \
680 do { \
681 v8::Isolate* isolate = target->GetIsolate(); \
682 v8::Local<v8::String> constant_name = \
683 v8::String::NewFromUtf8(isolate, name).ToLocalChecked(); \
684 v8::Local<v8::String> constant_value = \
685 v8::String::NewFromUtf8(isolate, constant).ToLocalChecked(); \
686 v8::PropertyAttribute constant_attributes = \
687 static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); \
688 target \
689 ->DefineOwnProperty(isolate->GetCurrentContext(), \
690 constant_name, \
691 constant_value, \
692 constant_attributes) \
693 .Check(); \
694 } while (0)
695
696 enum Endianness {
697 kLittleEndian, // _Not_ LITTLE_ENDIAN, clashes with endian.h.
698 kBigEndian
699 };
700
701 inline enum Endianness GetEndianness() {
702 // Constant-folded by the compiler.
703 const union {
704 uint8_t u8[2];
705 uint16_t u16;
706 } u = {{1, 0}};
707 return u.u16 == 1 ? kLittleEndian : kBigEndian;
708 }
709
710 inline bool IsLittleEndian() {
711 return GetEndianness() == kLittleEndian;
712 }
713
714 inline bool IsBigEndian() {
715 return GetEndianness() == kBigEndian;
716 }
717
718 // Round up a to the next highest multiple of b.
719 template <typename T>
720 constexpr T RoundUp(T a, T b) {
721 return a % b != 0 ? a + b - (a % b) : a;
722 }
723
724 // Align ptr to an `alignment`-bytes boundary.
725 template <typename T, typename U>
726 constexpr T* AlignUp(T* ptr, U alignment) {
727 return reinterpret_cast<T*>(
728 RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment));
729 }
730
731 class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> {
732 public:
733 inline explicit SlicedArguments(
734 const v8::FunctionCallbackInfo<v8::Value>& args, size_t start = 0);
735 };
736
737 // Convert a v8::PersistentBase, e.g. v8::Global, to a Local, with an extra
738 // optimization for strong persistent handles.
739 class PersistentToLocal {
740 public:
741 // If persistent.IsWeak() == false, then do not call persistent.Reset()
742 // while the returned Local<T> is still in scope, it will destroy the
743 // reference to the object.
744 template <class TypeName>
745 static inline v8::Local<TypeName> Default(
746 v8::Isolate* isolate,
747 const v8::PersistentBase<TypeName>& persistent) {
748 if (persistent.IsWeak()) {
749 return PersistentToLocal::Weak(isolate, persistent);
750 } else {
751 return PersistentToLocal::Strong(persistent);
752 }
753 }
754
755 // Unchecked conversion from a non-weak Persistent<T> to Local<T>,
756 // use with care!
757 //
758 // Do not call persistent.Reset() while the returned Local<T> is still in
759 // scope, it will destroy the reference to the object.
760 template <class TypeName>
761 static inline v8::Local<TypeName> Strong(
762 const v8::PersistentBase<TypeName>& persistent) {
763 DCHECK(!persistent.IsWeak());
764 return *reinterpret_cast<v8::Local<TypeName>*>(
765 const_cast<v8::PersistentBase<TypeName>*>(&persistent));
766 }
767
768 template <class TypeName>
769 static inline v8::Local<TypeName> Weak(
770 v8::Isolate* isolate,
771 const v8::PersistentBase<TypeName>& persistent) {
772 return v8::Local<TypeName>::New(isolate, persistent);
773 }
774 };
775
776 // Can be used as a key for std::unordered_map when lookup performance is more
777 // important than size and the keys are statically used to avoid redundant hash
778 // computations.
779 class FastStringKey {
780 public:
781 constexpr explicit FastStringKey(const char* name);
782
783 struct Hash {
784 constexpr size_t operator()(const FastStringKey& key) const;
785 };
786 constexpr bool operator==(const FastStringKey& other) const;
787
788 constexpr const char* c_str() const;
789
790 private:
791 static constexpr size_t HashImpl(const char* str);
792
793 const char* name_;
794 size_t cached_hash_;
795 };
796
797 // Like std::static_pointer_cast but for unique_ptr with the default deleter.
798 template <typename T, typename U>
799 std::unique_ptr<T> static_unique_pointer_cast(std::unique_ptr<U>&& ptr) {
800 return std::unique_ptr<T>(static_cast<T*>(ptr.release()));
801 }
802
803 // Returns a non-zero code if it fails to open or read the file,
804 // aborts if it fails to close the file.
805 int ReadFileSync(std::string* result, const char* path);
806 } // namespace node
807
808 #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
809
810 #endif // SRC_UTIL_H_
811