• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 // TAILQ-style intrusive list node.
199 template <typename T>
200 class ListNode;
201 
202 // TAILQ-style intrusive list head.
203 template <typename T, ListNode<T> (T::*M)>
204 class ListHead;
205 
206 template <typename T>
207 class ListNode {
208  public:
209   inline ListNode();
210   inline ~ListNode();
211   inline void Remove();
212   inline bool IsEmpty() const;
213 
214   ListNode(const ListNode&) = delete;
215   ListNode& operator=(const ListNode&) = delete;
216 
217  private:
218   template <typename U, ListNode<U> (U::*M)> friend class ListHead;
219   friend int GenDebugSymbols();
220   ListNode* prev_;
221   ListNode* next_;
222 };
223 
224 template <typename T, ListNode<T> (T::*M)>
225 class ListHead {
226  public:
227   class Iterator {
228    public:
229     inline T* operator*() const;
230     inline const Iterator& operator++();
231     inline bool operator!=(const Iterator& that) const;
232 
233    private:
234     friend class ListHead;
235     inline explicit Iterator(ListNode<T>* node);
236     ListNode<T>* node_;
237   };
238 
239   inline ListHead() = default;
240   inline ~ListHead();
241   inline void PushBack(T* element);
242   inline void PushFront(T* element);
243   inline bool IsEmpty() const;
244   inline T* PopFront();
245   inline Iterator begin() const;
246   inline Iterator end() const;
247 
248   ListHead(const ListHead&) = delete;
249   ListHead& operator=(const ListHead&) = delete;
250 
251  private:
252   friend int GenDebugSymbols();
253   ListNode<T> head_;
254 };
255 
256 // The helper is for doing safe downcasts from base types to derived types.
257 template <typename Inner, typename Outer>
258 class ContainerOfHelper {
259  public:
260   inline ContainerOfHelper(Inner Outer::*field, Inner* pointer);
261   template <typename TypeName>
262   inline operator TypeName*() const;
263  private:
264   Outer* const pointer_;
265 };
266 
267 // Calculate the address of the outer (i.e. embedding) struct from
268 // the interior pointer to a data member.
269 template <typename Inner, typename Outer>
270 constexpr ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
271                                                       Inner* pointer);
272 
273 // Convenience wrapper around v8::String::NewFromOneByte().
274 inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
275                                            const char* data,
276                                            int length = -1);
277 
278 // For the people that compile with -funsigned-char.
279 inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
280                                            const signed char* data,
281                                            int length = -1);
282 
283 inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
284                                            const unsigned char* data,
285                                            int length = -1);
286 
287 // Used to be a macro, hence the uppercase name.
288 template <int N>
FIXED_ONE_BYTE_STRING(v8::Isolate * isolate,const char (& data)[N])289 inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
290     v8::Isolate* isolate,
291     const char(&data)[N]) {
292   return OneByteString(isolate, data, N - 1);
293 }
294 
295 template <std::size_t N>
FIXED_ONE_BYTE_STRING(v8::Isolate * isolate,const std::array<char,N> & arr)296 inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
297     v8::Isolate* isolate,
298     const std::array<char, N>& arr) {
299   return OneByteString(isolate, arr.data(), N - 1);
300 }
301 
302 
303 
304 // Swaps bytes in place. nbytes is the number of bytes to swap and must be a
305 // multiple of the word size (checked by function).
306 inline void SwapBytes16(char* data, size_t nbytes);
307 inline void SwapBytes32(char* data, size_t nbytes);
308 inline void SwapBytes64(char* data, size_t nbytes);
309 
310 // tolower() is locale-sensitive.  Use ToLower() instead.
311 inline char ToLower(char c);
312 inline std::string ToLower(const std::string& in);
313 
314 // toupper() is locale-sensitive.  Use ToUpper() instead.
315 inline char ToUpper(char c);
316 inline std::string ToUpper(const std::string& in);
317 
318 // strcasecmp() is locale-sensitive.  Use StringEqualNoCase() instead.
319 inline bool StringEqualNoCase(const char* a, const char* b);
320 
321 // strncasecmp() is locale-sensitive.  Use StringEqualNoCaseN() instead.
322 inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length);
323 
324 template <typename T, size_t N>
arraysize(const T (&)[N])325 constexpr size_t arraysize(const T (&)[N]) {
326   return N;
327 }
328 
329 // Allocates an array of member type T. For up to kStackStorageSize items,
330 // the stack is used, otherwise malloc().
331 template <typename T, size_t kStackStorageSize = 1024>
332 class MaybeStackBuffer {
333  public:
out()334   const T* out() const {
335     return buf_;
336   }
337 
out()338   T* out() {
339     return buf_;
340   }
341 
342   // operator* for compatibility with `v8::String::(Utf8)Value`
343   T* operator*() {
344     return buf_;
345   }
346 
347   const T* operator*() const {
348     return buf_;
349   }
350 
351   T& operator[](size_t index) {
352     CHECK_LT(index, length());
353     return buf_[index];
354   }
355 
356   const T& operator[](size_t index) const {
357     CHECK_LT(index, length());
358     return buf_[index];
359   }
360 
length()361   size_t length() const {
362     return length_;
363   }
364 
365   // Current maximum capacity of the buffer with which SetLength() can be used
366   // without first calling AllocateSufficientStorage().
capacity()367   size_t capacity() const {
368     return capacity_;
369   }
370 
371   // Make sure enough space for `storage` entries is available.
372   // This method can be called multiple times throughout the lifetime of the
373   // buffer, but once this has been called Invalidate() cannot be used.
374   // Content of the buffer in the range [0, length()) is preserved.
AllocateSufficientStorage(size_t storage)375   void AllocateSufficientStorage(size_t storage) {
376     CHECK(!IsInvalidated());
377     if (storage > capacity()) {
378       bool was_allocated = IsAllocated();
379       T* allocated_ptr = was_allocated ? buf_ : nullptr;
380       buf_ = Realloc(allocated_ptr, storage);
381       capacity_ = storage;
382       if (!was_allocated && length_ > 0)
383         memcpy(buf_, buf_st_, length_ * sizeof(buf_[0]));
384     }
385 
386     length_ = storage;
387   }
388 
SetLength(size_t length)389   void SetLength(size_t length) {
390     // capacity() returns how much memory is actually available.
391     CHECK_LE(length, capacity());
392     length_ = length;
393   }
394 
SetLengthAndZeroTerminate(size_t length)395   void SetLengthAndZeroTerminate(size_t length) {
396     // capacity() returns how much memory is actually available.
397     CHECK_LE(length + 1, capacity());
398     SetLength(length);
399 
400     // T() is 0 for integer types, nullptr for pointers, etc.
401     buf_[length] = T();
402   }
403 
404   // Make derefencing this object return nullptr.
405   // This method can be called multiple times throughout the lifetime of the
406   // buffer, but once this has been called AllocateSufficientStorage() cannot
407   // be used.
Invalidate()408   void Invalidate() {
409     CHECK(!IsAllocated());
410     capacity_ = 0;
411     length_ = 0;
412     buf_ = nullptr;
413   }
414 
415   // If the buffer is stored in the heap rather than on the stack.
IsAllocated()416   bool IsAllocated() const {
417     return !IsInvalidated() && buf_ != buf_st_;
418   }
419 
420   // If Invalidate() has been called.
IsInvalidated()421   bool IsInvalidated() const {
422     return buf_ == nullptr;
423   }
424 
425   // Release ownership of the malloc'd buffer.
426   // Note: This does not free the buffer.
Release()427   void Release() {
428     CHECK(IsAllocated());
429     buf_ = buf_st_;
430     length_ = 0;
431     capacity_ = arraysize(buf_st_);
432   }
433 
MaybeStackBuffer()434   MaybeStackBuffer()
435       : length_(0), capacity_(arraysize(buf_st_)), buf_(buf_st_) {
436     // Default to a zero-length, null-terminated buffer.
437     buf_[0] = T();
438   }
439 
MaybeStackBuffer(size_t storage)440   explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() {
441     AllocateSufficientStorage(storage);
442   }
443 
~MaybeStackBuffer()444   ~MaybeStackBuffer() {
445     if (IsAllocated())
446       free(buf_);
447   }
448 
449  private:
450   size_t length_;
451   // capacity of the malloc'ed buf_
452   size_t capacity_;
453   T* buf_;
454   T buf_st_[kStackStorageSize];
455 };
456 
457 // Provides access to an ArrayBufferView's storage, either the original,
458 // or for small data, a copy of it. This object's lifetime is bound to the
459 // original ArrayBufferView's lifetime.
460 template <typename T, size_t kStackStorageSize = 64>
461 class ArrayBufferViewContents {
462  public:
463   ArrayBufferViewContents() = default;
464 
465   explicit inline ArrayBufferViewContents(v8::Local<v8::Value> value);
466   explicit inline ArrayBufferViewContents(v8::Local<v8::Object> value);
467   explicit inline ArrayBufferViewContents(v8::Local<v8::ArrayBufferView> abv);
468   inline void Read(v8::Local<v8::ArrayBufferView> abv);
469 
data()470   inline const T* data() const { return data_; }
length()471   inline size_t length() const { return length_; }
472 
473  private:
474   T stack_storage_[kStackStorageSize];
475   T* data_ = nullptr;
476   size_t length_ = 0;
477 };
478 
479 class Utf8Value : public MaybeStackBuffer<char> {
480  public:
481   explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
482 
ToString()483   inline std::string ToString() const { return std::string(out(), length()); }
484 
485   inline bool operator==(const char* a) const {
486     return strcmp(out(), a) == 0;
487   }
488 };
489 
490 class TwoByteValue : public MaybeStackBuffer<uint16_t> {
491  public:
492   explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
493 };
494 
495 class BufferValue : public MaybeStackBuffer<char> {
496  public:
497   explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
498 
ToString()499   inline std::string ToString() const { return std::string(out(), length()); }
500 };
501 
502 #define SPREAD_BUFFER_ARG(val, name)                                          \
503   CHECK((val)->IsArrayBufferView());                                          \
504   v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>();      \
505   v8::ArrayBuffer::Contents name##_c = name->Buffer()->GetContents();         \
506   const size_t name##_offset = name->ByteOffset();                            \
507   const size_t name##_length = name->ByteLength();                            \
508   char* const name##_data =                                                   \
509       static_cast<char*>(name##_c.Data()) + name##_offset;                    \
510   if (name##_length > 0)                                                      \
511     CHECK_NE(name##_data, nullptr);
512 
513 // Use this when a variable or parameter is unused in order to explicitly
514 // silence a compiler warning about that.
USE(T &&)515 template <typename T> inline void USE(T&&) {}
516 
517 template <typename Fn>
518 struct OnScopeLeaveImpl {
519   Fn fn_;
520   bool active_;
521 
OnScopeLeaveImplOnScopeLeaveImpl522   explicit OnScopeLeaveImpl(Fn&& fn) : fn_(std::move(fn)), active_(true) {}
~OnScopeLeaveImplOnScopeLeaveImpl523   ~OnScopeLeaveImpl() { if (active_) fn_(); }
524 
525   OnScopeLeaveImpl(const OnScopeLeaveImpl& other) = delete;
526   OnScopeLeaveImpl& operator=(const OnScopeLeaveImpl& other) = delete;
OnScopeLeaveImplOnScopeLeaveImpl527   OnScopeLeaveImpl(OnScopeLeaveImpl&& other)
528     : fn_(std::move(other.fn_)), active_(other.active_) {
529     other.active_ = false;
530   }
531   OnScopeLeaveImpl& operator=(OnScopeLeaveImpl&& other) {
532     if (this == &other) return *this;
533     this->~OnScopeLeave();
534     new (this)OnScopeLeaveImpl(std::move(other));
535     return *this;
536   }
537 };
538 
539 // Run a function when exiting the current scope. Used like this:
540 // auto on_scope_leave = OnScopeLeave([&] {
541 //   // ... run some code ...
542 // });
543 template <typename Fn>
OnScopeLeave(Fn && fn)544 inline MUST_USE_RESULT OnScopeLeaveImpl<Fn> OnScopeLeave(Fn&& fn) {
545   return OnScopeLeaveImpl<Fn>{std::move(fn)};
546 }
547 
548 // Simple RAII wrapper for contiguous data that uses malloc()/free().
549 template <typename T>
550 struct MallocedBuffer {
551   T* data;
552   size_t size;
553 
releaseMallocedBuffer554   T* release() {
555     T* ret = data;
556     data = nullptr;
557     return ret;
558   }
559 
TruncateMallocedBuffer560   void Truncate(size_t new_size) {
561     CHECK(new_size <= size);
562     size = new_size;
563   }
564 
is_emptyMallocedBuffer565   inline bool is_empty() const { return data == nullptr; }
566 
MallocedBufferMallocedBuffer567   MallocedBuffer() : data(nullptr), size(0) {}
MallocedBufferMallocedBuffer568   explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {}
MallocedBufferMallocedBuffer569   MallocedBuffer(T* data, size_t size) : data(data), size(size) {}
MallocedBufferMallocedBuffer570   MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) {
571     other.data = nullptr;
572   }
573   MallocedBuffer& operator=(MallocedBuffer&& other) {
574     this->~MallocedBuffer();
575     return *new(this) MallocedBuffer(std::move(other));
576   }
~MallocedBufferMallocedBuffer577   ~MallocedBuffer() {
578     free(data);
579   }
580   MallocedBuffer(const MallocedBuffer&) = delete;
581   MallocedBuffer& operator=(const MallocedBuffer&) = delete;
582 };
583 
584 template <typename T>
585 class NonCopyableMaybe {
586  public:
NonCopyableMaybe()587   NonCopyableMaybe() : empty_(true) {}
NonCopyableMaybe(T && value)588   explicit NonCopyableMaybe(T&& value)
589       : empty_(false),
590         value_(std::move(value)) {}
591 
IsEmpty()592   bool IsEmpty() const {
593     return empty_;
594   }
595 
Release()596   T&& Release() {
597     CHECK_EQ(empty_, false);
598     empty_ = true;
599     return std::move(value_);
600   }
601 
602  private:
603   bool empty_;
604   T value_;
605 };
606 
607 // Test whether some value can be called with ().
608 template <typename T, typename = void>
609 struct is_callable : std::is_function<T> { };
610 
611 template <typename T>
612 struct is_callable<T, typename std::enable_if<
613     std::is_same<decltype(void(&T::operator())), void>::value
614     >::type> : std::true_type { };
615 
616 template <typename T, void (*function)(T*)>
617 struct FunctionDeleter {
618   void operator()(T* pointer) const { function(pointer); }
619   typedef std::unique_ptr<T, FunctionDeleter> Pointer;
620 };
621 
622 template <typename T, void (*function)(T*)>
623 using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
624 
625 std::vector<std::string> SplitString(const std::string& in, char delim);
626 
627 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
628                                            const std::string& str,
629                                            v8::Isolate* isolate = nullptr);
630 template <typename T, typename test_for_number =
631     typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
632 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
633                                            const T& number,
634                                            v8::Isolate* isolate = nullptr);
635 template <typename T>
636 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
637                                            const std::vector<T>& vec,
638                                            v8::Isolate* isolate = nullptr);
639 template <typename T, typename U>
640 inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
641                                            const std::unordered_map<T, U>& map,
642                                            v8::Isolate* isolate = nullptr);
643 
644 // These macros expects a `Isolate* isolate` and a `Local<Context> context`
645 // to be in the scope.
646 #define READONLY_PROPERTY(obj, name, value)                                    \
647   do {                                                                         \
648     obj->DefineOwnProperty(                                                    \
649            context, FIXED_ONE_BYTE_STRING(isolate, name), value, v8::ReadOnly) \
650         .Check();                                                              \
651   } while (0)
652 
653 #define READONLY_DONT_ENUM_PROPERTY(obj, name, var)                            \
654   do {                                                                         \
655     obj->DefineOwnProperty(                                                    \
656            context,                                                            \
657            OneByteString(isolate, name),                                       \
658            var,                                                                \
659            static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum))    \
660         .Check();                                                              \
661   } while (0)
662 
663 #define READONLY_FALSE_PROPERTY(obj, name)                                     \
664   READONLY_PROPERTY(obj, name, v8::False(isolate))
665 
666 #define READONLY_TRUE_PROPERTY(obj, name)                                      \
667   READONLY_PROPERTY(obj, name, v8::True(isolate))
668 
669 #define READONLY_STRING_PROPERTY(obj, name, str)                               \
670   READONLY_PROPERTY(obj, name, ToV8Value(context, str).ToLocalChecked())
671 
672 // Variation on NODE_DEFINE_CONSTANT that sets a String value.
673 #define NODE_DEFINE_STRING_CONSTANT(target, name, constant)                    \
674   do {                                                                         \
675     v8::Isolate* isolate = target->GetIsolate();                               \
676     v8::Local<v8::String> constant_name =                                      \
677         v8::String::NewFromUtf8(isolate, name, v8::NewStringType::kNormal)     \
678             .ToLocalChecked();                                                 \
679     v8::Local<v8::String> constant_value =                                     \
680         v8::String::NewFromUtf8(isolate, constant, v8::NewStringType::kNormal) \
681             .ToLocalChecked();                                                 \
682     v8::PropertyAttribute constant_attributes =                                \
683         static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);     \
684     target                                                                     \
685         ->DefineOwnProperty(isolate->GetCurrentContext(),                      \
686                             constant_name,                                     \
687                             constant_value,                                    \
688                             constant_attributes)                               \
689         .Check();                                                              \
690   } while (0)
691 
692 enum Endianness {
693   kLittleEndian,  // _Not_ LITTLE_ENDIAN, clashes with endian.h.
694   kBigEndian
695 };
696 
697 inline enum Endianness GetEndianness() {
698   // Constant-folded by the compiler.
699   const union {
700     uint8_t u8[2];
701     uint16_t u16;
702   } u = {{1, 0}};
703   return u.u16 == 1 ? kLittleEndian : kBigEndian;
704 }
705 
706 inline bool IsLittleEndian() {
707   return GetEndianness() == kLittleEndian;
708 }
709 
710 inline bool IsBigEndian() {
711   return GetEndianness() == kBigEndian;
712 }
713 
714 // Round up a to the next highest multiple of b.
715 template <typename T>
716 constexpr T RoundUp(T a, T b) {
717   return a % b != 0 ? a + b - (a % b) : a;
718 }
719 
720 class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> {
721  public:
722   inline explicit SlicedArguments(
723       const v8::FunctionCallbackInfo<v8::Value>& args, size_t start = 0);
724 };
725 
726 // Convert a v8::PersistentBase, e.g. v8::Global, to a Local, with an extra
727 // optimization for strong persistent handles.
728 class PersistentToLocal {
729  public:
730   // If persistent.IsWeak() == false, then do not call persistent.Reset()
731   // while the returned Local<T> is still in scope, it will destroy the
732   // reference to the object.
733   template <class TypeName>
734   static inline v8::Local<TypeName> Default(
735       v8::Isolate* isolate,
736       const v8::PersistentBase<TypeName>& persistent) {
737     if (persistent.IsWeak()) {
738       return PersistentToLocal::Weak(isolate, persistent);
739     } else {
740       return PersistentToLocal::Strong(persistent);
741     }
742   }
743 
744   // Unchecked conversion from a non-weak Persistent<T> to Local<T>,
745   // use with care!
746   //
747   // Do not call persistent.Reset() while the returned Local<T> is still in
748   // scope, it will destroy the reference to the object.
749   template <class TypeName>
750   static inline v8::Local<TypeName> Strong(
751       const v8::PersistentBase<TypeName>& persistent) {
752     return *reinterpret_cast<v8::Local<TypeName>*>(
753         const_cast<v8::PersistentBase<TypeName>*>(&persistent));
754   }
755 
756   template <class TypeName>
757   static inline v8::Local<TypeName> Weak(
758       v8::Isolate* isolate,
759       const v8::PersistentBase<TypeName>& persistent) {
760     return v8::Local<TypeName>::New(isolate, persistent);
761   }
762 };
763 
764 // Like std::static_pointer_cast but for unique_ptr with the default deleter.
765 template <typename T, typename U>
766 std::unique_ptr<T> static_unique_pointer_cast(std::unique_ptr<U>&& ptr) {
767   return std::unique_ptr<T>(static_cast<T*>(ptr.release()));
768 }
769 
770 }  // namespace node
771 
772 #endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
773 
774 #endif  // SRC_UTIL_H_
775