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