• 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 // 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