GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/util.h Lines: 125 125 100.0 %
Date: 2020-02-27 22:14:15 Branches: 77 124 62.1 %

Line Branch Exec Source
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 <cassert>
37
#include <climits>  // PATH_MAX
38
#include <csignal>
39
#include <cstddef>
40
#include <cstdio>
41
#include <cstdlib>
42
#include <cstring>
43
44
#include <functional>  // std::function
45
#include <limits>
46
#include <set>
47
#include <string>
48
#include <array>
49
#include <unordered_map>
50
#include <utility>
51
52
#ifdef __GNUC__
53
#define MUST_USE_RESULT __attribute__((warn_unused_result))
54
#else
55
#define MUST_USE_RESULT
56
#endif
57
58
namespace node {
59
60
// Maybe remove kPathSeparator when cpp17 is ready
61
#ifdef _WIN32
62
    constexpr char kPathSeparator = '\\';
63
/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */
64
#define PATH_MAX_BYTES (MAX_PATH * 4)
65
#else
66
    constexpr char kPathSeparator = '/';
67
#define PATH_MAX_BYTES (PATH_MAX)
68
#endif
69
70
// These should be used in our code as opposed to the native
71
// versions as they abstract out some platform and or
72
// compiler version specific functionality
73
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
74
// that the standard allows them to either return a unique pointer or a
75
// nullptr for zero-sized allocation requests.  Normalize by always using
76
// a nullptr.
77
template <typename T>
78
inline T* UncheckedRealloc(T* pointer, size_t n);
79
template <typename T>
80
inline T* UncheckedMalloc(size_t n);
81
template <typename T>
82
inline T* UncheckedCalloc(size_t n);
83
84
// Same things, but aborts immediately instead of returning nullptr when
85
// no memory is available.
86
template <typename T>
87
inline T* Realloc(T* pointer, size_t n);
88
template <typename T>
89
inline T* Malloc(size_t n);
90
template <typename T>
91
inline T* Calloc(size_t n);
92
93
inline char* Malloc(size_t n);
94
inline char* Calloc(size_t n);
95
inline char* UncheckedMalloc(size_t n);
96
inline char* UncheckedCalloc(size_t n);
97
98
template <typename T>
99
inline T MultiplyWithOverflowCheck(T a, T b);
100
101
namespace per_process {
102
// Tells whether the per-process V8::Initialize() is called and
103
// if it is safe to call v8::Isolate::GetCurrent().
104
extern bool v8_initialized;
105
}  // namespace per_process
106
107
// Used by the allocation functions when allocation fails.
108
// Thin wrapper around v8::Isolate::LowMemoryNotification() that checks
109
// whether V8 is initialized.
110
void LowMemoryNotification();
111
112
// The reason that Assert() takes a struct argument instead of individual
113
// const char*s is to ease instruction cache pressure in calls from CHECK.
114
struct AssertionInfo {
115
  const char* file_line;  // filename:line
116
  const char* message;
117
  const char* function;
118
};
119
[[noreturn]] void Assert(const AssertionInfo& info);
120
[[noreturn]] void Abort();
121
void DumpBacktrace(FILE* fp);
122
123
// Windows 8+ does not like abort() in Release mode
124
#ifdef _WIN32
125
#define ABORT_NO_BACKTRACE() _exit(134)
126
#else
127
#define ABORT_NO_BACKTRACE() abort()
128
#endif
129
130
#define ABORT() node::Abort()
131
132
#define ERROR_AND_ABORT(expr)                                                 \
133
  do {                                                                        \
134
    /* Make sure that this struct does not end up in inline code, but      */ \
135
    /* rather in a read-only data section when modifying this code.        */ \
136
    static const node::AssertionInfo args = {                                 \
137
      __FILE__ ":" STRINGIFY(__LINE__), #expr, PRETTY_FUNCTION_NAME           \
138
    };                                                                        \
139
    node::Assert(args);                                                       \
140
  } while (0)
141
142
#ifdef __GNUC__
143
#define LIKELY(expr) __builtin_expect(!!(expr), 1)
144
#define UNLIKELY(expr) __builtin_expect(!!(expr), 0)
145
#define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__
146
#else
147
#define LIKELY(expr) expr
148
#define UNLIKELY(expr) expr
149
#define PRETTY_FUNCTION_NAME ""
150
#endif
151
152
#define STRINGIFY_(x) #x
153
#define STRINGIFY(x) STRINGIFY_(x)
154
155
#define CHECK(expr)                                                           \
156
  do {                                                                        \
157
    if (UNLIKELY(!(expr))) {                                                  \
158
      ERROR_AND_ABORT(expr);                                                  \
159
    }                                                                         \
160
  } while (0)
161
162
#define CHECK_EQ(a, b) CHECK((a) == (b))
163
#define CHECK_GE(a, b) CHECK((a) >= (b))
164
#define CHECK_GT(a, b) CHECK((a) > (b))
165
#define CHECK_LE(a, b) CHECK((a) <= (b))
166
#define CHECK_LT(a, b) CHECK((a) < (b))
167
#define CHECK_NE(a, b) CHECK((a) != (b))
168
#define CHECK_NULL(val) CHECK((val) == nullptr)
169
#define CHECK_NOT_NULL(val) CHECK((val) != nullptr)
170
#define CHECK_IMPLIES(a, b) CHECK(!(a) || (b))
171
172
#ifdef DEBUG
173
  #define DCHECK(expr) CHECK(expr)
174
  #define DCHECK_EQ(a, b) CHECK((a) == (b))
175
  #define DCHECK_GE(a, b) CHECK((a) >= (b))
176
  #define DCHECK_GT(a, b) CHECK((a) > (b))
177
  #define DCHECK_LE(a, b) CHECK((a) <= (b))
178
  #define DCHECK_LT(a, b) CHECK((a) < (b))
179
  #define DCHECK_NE(a, b) CHECK((a) != (b))
180
  #define DCHECK_NULL(val) CHECK((val) == nullptr)
181
  #define DCHECK_NOT_NULL(val) CHECK((val) != nullptr)
182
  #define DCHECK_IMPLIES(a, b) CHECK(!(a) || (b))
183
#else
184
  #define DCHECK(expr)
185
  #define DCHECK_EQ(a, b)
186
  #define DCHECK_GE(a, b)
187
  #define DCHECK_GT(a, b)
188
  #define DCHECK_LE(a, b)
189
  #define DCHECK_LT(a, b)
190
  #define DCHECK_NE(a, b)
191
  #define DCHECK_NULL(val)
192
  #define DCHECK_NOT_NULL(val)
193
  #define DCHECK_IMPLIES(a, b)
194
#endif
195
196
197
#define UNREACHABLE(...)                                                      \
198
  ERROR_AND_ABORT("Unreachable code reached" __VA_OPT__(": ") __VA_ARGS__)
199
200
// ECMA262 20.1.2.6 Number.MAX_SAFE_INTEGER (2^53-1)
201
constexpr int64_t kMaxSafeJsInteger = 9007199254740991;
202
203
inline bool IsSafeJsInt(v8::Local<v8::Value> v);
204
205
// TAILQ-style intrusive list node.
206
template <typename T>
207
class ListNode;
208
209
// TAILQ-style intrusive list head.
210
template <typename T, ListNode<T> (T::*M)>
211
class ListHead;
212
213
template <typename T>
214
class ListNode {
215
 public:
216
  inline ListNode();
217
  inline ~ListNode();
218
  inline void Remove();
219
  inline bool IsEmpty() const;
220
221
  ListNode(const ListNode&) = delete;
222
  ListNode& operator=(const ListNode&) = delete;
223
224
 private:
225
  template <typename U, ListNode<U> (U::*M)> friend class ListHead;
226
  friend int GenDebugSymbols();
227
  ListNode* prev_;
228
  ListNode* next_;
229
};
230
231
template <typename T, ListNode<T> (T::*M)>
232
class ListHead {
233
 public:
234
  class Iterator {
235
   public:
236
    inline T* operator*() const;
237
    inline const Iterator& operator++();
238
    inline bool operator!=(const Iterator& that) const;
239
240
   private:
241
    friend class ListHead;
242
    inline explicit Iterator(ListNode<T>* node);
243
    ListNode<T>* node_;
244
  };
245
246
8785
  inline ListHead() = default;
247
  inline ~ListHead();
248
  inline void PushBack(T* element);
249
  inline void PushFront(T* element);
250
  inline bool IsEmpty() const;
251
  inline T* PopFront();
252
  inline Iterator begin() const;
253
  inline Iterator end() const;
254
255
  ListHead(const ListHead&) = delete;
256
  ListHead& operator=(const ListHead&) = delete;
257
258
 private:
259
  friend int GenDebugSymbols();
260
  ListNode<T> head_;
261
};
262
263
// The helper is for doing safe downcasts from base types to derived types.
264
template <typename Inner, typename Outer>
265
class ContainerOfHelper {
266
 public:
267
  inline ContainerOfHelper(Inner Outer::*field, Inner* pointer);
268
  template <typename TypeName>
269
  inline operator TypeName*() const;
270
 private:
271
  Outer* const pointer_;
272
};
273
274
// Calculate the address of the outer (i.e. embedding) struct from
275
// the interior pointer to a data member.
276
template <typename Inner, typename Outer>
277
constexpr ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field,
278
                                                      Inner* pointer);
279
280
// Convenience wrapper around v8::String::NewFromOneByte().
281
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
282
                                           const char* data,
283
                                           int length = -1);
284
285
// For the people that compile with -funsigned-char.
286
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
287
                                           const signed char* data,
288
                                           int length = -1);
289
290
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate,
291
                                           const unsigned char* data,
292
                                           int length = -1);
293
294
// Used to be a macro, hence the uppercase name.
295
template <int N>
296
3547687
inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
297
    v8::Isolate* isolate,
298
    const char(&data)[N]) {
299
3547687
  return OneByteString(isolate, data, N - 1);
300
}
301
302
template <std::size_t N>
303
510
inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING(
304
    v8::Isolate* isolate,
305
    const std::array<char, N>& arr) {
306
510
  return OneByteString(isolate, arr.data(), N - 1);
307
}
308
309
310
311
// Swaps bytes in place. nbytes is the number of bytes to swap and must be a
312
// multiple of the word size (checked by function).
313
inline void SwapBytes16(char* data, size_t nbytes);
314
inline void SwapBytes32(char* data, size_t nbytes);
315
inline void SwapBytes64(char* data, size_t nbytes);
316
317
// tolower() is locale-sensitive.  Use ToLower() instead.
318
inline char ToLower(char c);
319
inline std::string ToLower(const std::string& in);
320
321
// toupper() is locale-sensitive.  Use ToUpper() instead.
322
inline char ToUpper(char c);
323
inline std::string ToUpper(const std::string& in);
324
325
// strcasecmp() is locale-sensitive.  Use StringEqualNoCase() instead.
326
inline bool StringEqualNoCase(const char* a, const char* b);
327
328
// strncasecmp() is locale-sensitive.  Use StringEqualNoCaseN() instead.
329
inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length);
330
331
// Allocates an array of member type T. For up to kStackStorageSize items,
332
// the stack is used, otherwise malloc().
333
template <typename T, size_t kStackStorageSize = 1024>
334
class MaybeStackBuffer {
335
 public:
336
814
  const T* out() const {
337
814
    return buf_;
338
  }
339
340
4453581
  T* out() {
341
4453581
    return buf_;
342
  }
343
344
  // operator* for compatibility with `v8::String::(Utf8)Value`
345
4432342
  T* operator*() {
346
4432342
    return buf_;
347
  }
348
349
330345
  const T* operator*() const {
350
330345
    return buf_;
351
  }
352
353
3111162
  T& operator[](size_t index) {
354

3111162
    CHECK_LT(index, length());
355
3111162
    return buf_[index];
356
  }
357
358
10274
  const T& operator[](size_t index) const {
359
10274
    CHECK_LT(index, length());
360
10274
    return buf_[index];
361
  }
362
363
4381638
  size_t length() const {
364
4381638
    return length_;
365
  }
366
367
  // Current maximum capacity of the buffer with which SetLength() can be used
368
  // without first calling AllocateSufficientStorage().
369
11764852
  size_t capacity() const {
370


23196029
    return IsAllocated() ? capacity_ :
371


23196061
                           IsInvalidated() ? 0 : kStackStorageSize;
372
  }
373
374
  // Make sure enough space for `storage` entries is available.
375
  // This method can be called multiple times throughout the lifetime of the
376
  // buffer, but once this has been called Invalidate() cannot be used.
377
  // Content of the buffer in the range [0, length()) is preserved.
378
4184770
  void AllocateSufficientStorage(size_t storage) {
379


4184770
    CHECK(!IsInvalidated());
380


4184776
    if (storage > capacity()) {
381
326440
      bool was_allocated = IsAllocated();
382


326440
      T* allocated_ptr = was_allocated ? buf_ : nullptr;
383
326440
      buf_ = Realloc(allocated_ptr, storage);
384
326440
      capacity_ = storage;
385




326440
      if (!was_allocated && length_ > 0)
386
2
        memcpy(buf_, buf_st_, length_ * sizeof(buf_[0]));
387
    }
388
389
4184782
    length_ = storage;
390
4184782
  }
391
392
4083033
  void SetLength(size_t length) {
393
    // capacity() returns how much memory is actually available.
394

4083033
    CHECK_LE(length, capacity());
395
4083033
    length_ = length;
396
4083033
  }
397
398
3484609
  void SetLengthAndZeroTerminate(size_t length) {
399
    // capacity() returns how much memory is actually available.
400

3484609
    CHECK_LE(length + 1, capacity());
401
3484626
    SetLength(length);
402
403
    // T() is 0 for integer types, nullptr for pointers, etc.
404
3484626
    buf_[length] = T();
405
3484626
  }
406
407
  // Make derefencing this object return nullptr.
408
  // This method can be called multiple times throughout the lifetime of the
409
  // buffer, but once this has been called AllocateSufficientStorage() cannot
410
  // be used.
411
2
  void Invalidate() {
412
2
    CHECK(!IsAllocated());
413
2
    length_ = 0;
414
2
    buf_ = nullptr;
415
2
  }
416
417
  // If the buffer is stored in the heap rather than on the stack.
418
16841153
  bool IsAllocated() const {
419




16841153
    return !IsInvalidated() && buf_ != buf_st_;
420
  }
421
422
  // If Invalidate() has been called.
423
32462388
  bool IsInvalidated() const {
424
32462388
    return buf_ == nullptr;
425
  }
426
427
  // Release ownership of the malloc'd buffer.
428
  // Note: This does not free the buffer.
429
4
  void Release() {
430

4
    CHECK(IsAllocated());
431
4
    buf_ = buf_st_;
432
4
    length_ = 0;
433
4
    capacity_ = 0;
434
4
  }
435
436

68102873
  MaybeStackBuffer() : length_(0), capacity_(0), buf_(buf_st_) {
437
    // Default to a zero-length, null-terminated buffer.
438
5078151
    buf_[0] = T();
439
4737223
  }
440
441
283569
  explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() {
442
283570
    AllocateSufficientStorage(storage);
443
283569
  }
444
445
4736696
  ~MaybeStackBuffer() {
446


4736696
    if (IsAllocated())
447
326432
      free(buf_);
448
4736701
  }
449
450
 private:
451
  size_t length_;
452
  // capacity of the malloc'ed buf_
453
  size_t capacity_;
454
  T* buf_;
455
  T buf_st_[kStackStorageSize];
456
};
457
458
// Provides access to an ArrayBufferView's storage, either the original,
459
// or for small data, a copy of it. This object's lifetime is bound to the
460
// original ArrayBufferView's lifetime.
461
template <typename T, size_t kStackStorageSize = 64>
462
class ArrayBufferViewContents {
463
 public:
464
1815
  ArrayBufferViewContents() = default;
465
466
  explicit inline ArrayBufferViewContents(v8::Local<v8::Value> value);
467
  explicit inline ArrayBufferViewContents(v8::Local<v8::Object> value);
468
  explicit inline ArrayBufferViewContents(v8::Local<v8::ArrayBufferView> abv);
469
  inline void Read(v8::Local<v8::ArrayBufferView> abv);
470
471
546616
  inline const T* data() const { return data_; }
472
2146803
  inline size_t length() const { return length_; }
473
474
 private:
475
  T stack_storage_[kStackStorageSize];
476
  T* data_ = nullptr;
477
  size_t length_ = 0;
478
};
479
480
3293158
class Utf8Value : public MaybeStackBuffer<char> {
481
 public:
482
  explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
483
484
814
  inline std::string ToString() const { return std::string(out(), length()); }
485
};
486
487
2050
class TwoByteValue : public MaybeStackBuffer<uint16_t> {
488
 public:
489
  explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
490
};
491
492
188675
class BufferValue : public MaybeStackBuffer<char> {
493
 public:
494
  explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
495
496
  inline std::string ToString() const { return std::string(out(), length()); }
497
};
498
499
#define SPREAD_BUFFER_ARG(val, name)                                          \
500
  CHECK((val)->IsArrayBufferView());                                          \
501
  v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>();      \
502
  std::shared_ptr<v8::BackingStore> name##_bs =                               \
503
      name->Buffer()->GetBackingStore();                                      \
504
  const size_t name##_offset = name->ByteOffset();                            \
505
  const size_t name##_length = name->ByteLength();                            \
506
  char* const name##_data =                                                   \
507
      static_cast<char*>(name##_bs->Data()) + name##_offset;                  \
508
  if (name##_length > 0)                                                      \
509
    CHECK_NE(name##_data, nullptr);
510
511
// Use this when a variable or parameter is unused in order to explicitly
512
// silence a compiler warning about that.
513
3794744
template <typename T> inline void USE(T&&) {}
514
515
template <typename Fn>
516
struct OnScopeLeaveImpl {
517
  Fn fn_;
518
  bool active_;
519
520
646244
  explicit OnScopeLeaveImpl(Fn&& fn) : fn_(std::move(fn)), active_(true) {}
521

646144
  ~OnScopeLeaveImpl() { if (active_) fn_(); }
522
523
  OnScopeLeaveImpl(const OnScopeLeaveImpl& other) = delete;
524
  OnScopeLeaveImpl& operator=(const OnScopeLeaveImpl& other) = delete;
525
  OnScopeLeaveImpl(OnScopeLeaveImpl&& other)
526
    : fn_(std::move(other.fn_)), active_(other.active_) {
527
    other.active_ = false;
528
  }
529
  OnScopeLeaveImpl& operator=(OnScopeLeaveImpl&& other) {
530
    if (this == &other) return *this;
531
    this->~OnScopeLeave();
532
    new (this)OnScopeLeaveImpl(std::move(other));
533
    return *this;
534
  }
535
};
536
537
// Run a function when exiting the current scope. Used like this:
538
// auto on_scope_leave = OnScopeLeave([&] {
539
//   // ... run some code ...
540
// });
541
template <typename Fn>
542
646247
inline MUST_USE_RESULT OnScopeLeaveImpl<Fn> OnScopeLeave(Fn&& fn) {
543
646247
  return OnScopeLeaveImpl<Fn>{std::move(fn)};
544
}
545
546
// Simple RAII wrapper for contiguous data that uses malloc()/free().
547
template <typename T>
548
struct MallocedBuffer {
549
  T* data;
550
  size_t size;
551
552
  T* release() {
553
    T* ret = data;
554
    data = nullptr;
555
    return ret;
556
  }
557
558
  void Truncate(size_t new_size) {
559
    CHECK(new_size <= size);
560
    size = new_size;
561
  }
562
563
43134
  inline bool is_empty() const { return data == nullptr; }
564
565
180450
  MallocedBuffer() : data(nullptr), size(0) {}
566
4
  explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {}
567
43139
  MallocedBuffer(T* data, size_t size) : data(data), size(size) {}
568
382696
  MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) {
569
382696
    other.data = nullptr;
570
382696
  }
571
96607
  MallocedBuffer& operator=(MallocedBuffer&& other) {
572
96607
    this->~MallocedBuffer();
573
96622
    return *new(this) MallocedBuffer(std::move(other));
574
  }
575
605411
  ~MallocedBuffer() {
576
605411
    free(data);
577
605411
  }
578
  MallocedBuffer(const MallocedBuffer&) = delete;
579
  MallocedBuffer& operator=(const MallocedBuffer&) = delete;
580
};
581
582
template <typename T>
583
1338
class NonCopyableMaybe {
584
 public:
585
1
  NonCopyableMaybe() : empty_(true) {}
586
1337
  explicit NonCopyableMaybe(T&& value)
587
      : empty_(false),
588
1337
        value_(std::move(value)) {}
589
590
1338
  bool IsEmpty() const {
591
1338
    return empty_;
592
  }
593
594
1337
  T&& Release() {
595
1337
    CHECK_EQ(empty_, false);
596
1337
    empty_ = true;
597
1337
    return std::move(value_);
598
  }
599
600
 private:
601
  bool empty_;
602
  T value_;
603
};
604
605
// Test whether some value can be called with ().
606
template <typename T, typename = void>
607
struct is_callable : std::is_function<T> { };
608
609
template <typename T>
610
struct is_callable<T, typename std::enable_if<
611
    std::is_same<decltype(void(&T::operator())), void>::value
612
    >::type> : std::true_type { };
613
614
template <typename T, void (*function)(T*)>
615
struct FunctionDeleter {
616
384452
  void operator()(T* pointer) const { function(pointer); }
617
  typedef std::unique_ptr<T, FunctionDeleter> Pointer;
618
};
619
620
template <typename T, void (*function)(T*)>
621
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
622
623
std::vector<std::string> SplitString(const std::string& in, char delim);
624
625
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
626
                                           const std::string& str,
627
                                           v8::Isolate* isolate = nullptr);
628
template <typename T, typename test_for_number =
629
    typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
630
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
631
                                           const T& number,
632
                                           v8::Isolate* isolate = nullptr);
633
template <typename T>
634
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
635
                                           const std::vector<T>& vec,
636
                                           v8::Isolate* isolate = nullptr);
637
template <typename T, typename U>
638
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
639
                                           const std::unordered_map<T, U>& map,
640
                                           v8::Isolate* isolate = nullptr);
641
642
// These macros expects a `Isolate* isolate` and a `Local<Context> context`
643
// to be in the scope.
644
#define READONLY_PROPERTY(obj, name, value)                                    \
645
  do {                                                                         \
646
    obj->DefineOwnProperty(                                                    \
647
           context, FIXED_ONE_BYTE_STRING(isolate, name), value, v8::ReadOnly) \
648
        .Check();                                                              \
649
  } while (0)
650
651
#define READONLY_DONT_ENUM_PROPERTY(obj, name, var)                            \
652
  do {                                                                         \
653
    obj->DefineOwnProperty(                                                    \
654
           context,                                                            \
655
           OneByteString(isolate, name),                                       \
656
           var,                                                                \
657
           static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum))    \
658
        .Check();                                                              \
659
  } while (0)
660
661
#define READONLY_FALSE_PROPERTY(obj, name)                                     \
662
  READONLY_PROPERTY(obj, name, v8::False(isolate))
663
664
#define READONLY_TRUE_PROPERTY(obj, name)                                      \
665
  READONLY_PROPERTY(obj, name, v8::True(isolate))
666
667
#define READONLY_STRING_PROPERTY(obj, name, str)                               \
668
  READONLY_PROPERTY(obj, name, ToV8Value(context, str).ToLocalChecked())
669
670
// Variation on NODE_DEFINE_CONSTANT that sets a String value.
671
#define NODE_DEFINE_STRING_CONSTANT(target, name, constant)                    \
672
  do {                                                                         \
673
    v8::Isolate* isolate = target->GetIsolate();                               \
674
    v8::Local<v8::String> constant_name =                                      \
675
        v8::String::NewFromUtf8(isolate, name, v8::NewStringType::kNormal)     \
676
            .ToLocalChecked();                                                 \
677
    v8::Local<v8::String> constant_value =                                     \
678
        v8::String::NewFromUtf8(isolate, constant, v8::NewStringType::kNormal) \
679
            .ToLocalChecked();                                                 \
680
    v8::PropertyAttribute constant_attributes =                                \
681
        static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);     \
682
    target                                                                     \
683
        ->DefineOwnProperty(isolate->GetCurrentContext(),                      \
684
                            constant_name,                                     \
685
                            constant_value,                                    \
686
                            constant_attributes)                               \
687
        .Check();                                                              \
688
  } while (0)
689
690
enum Endianness {
691
  kLittleEndian,  // _Not_ LITTLE_ENDIAN, clashes with endian.h.
692
  kBigEndian
693
};
694
695
18576
inline enum Endianness GetEndianness() {
696
  // Constant-folded by the compiler.
697
  const union {
698
    uint8_t u8[2];
699
    uint16_t u16;
700
18576
  } u = {{1, 0}};
701
18576
  return u.u16 == 1 ? kLittleEndian : kBigEndian;
702
}
703
704
1
inline bool IsLittleEndian() {
705
1
  return GetEndianness() == kLittleEndian;
706
}
707
708
18575
inline bool IsBigEndian() {
709
18575
  return GetEndianness() == kBigEndian;
710
}
711
712
template <typename T, size_t N>
713
1686050
constexpr size_t arraysize(const T (&)[N]) {
714
1686050
  return N;
715
}
716
717
// Round up a to the next highest multiple of b.
718
template <typename T>
719
112363
constexpr T RoundUp(T a, T b) {
720
112363
  return a % b != 0 ? a + b - (a % b) : a;
721
}
722
723
27170
class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> {
724
 public:
725
  inline explicit SlicedArguments(
726
      const v8::FunctionCallbackInfo<v8::Value>& args, size_t start = 0);
727
};
728
729
// Convert a v8::PersistentBase, e.g. v8::Global, to a Local, with an extra
730
// optimization for strong persistent handles.
731
class PersistentToLocal {
732
 public:
733
  // If persistent.IsWeak() == false, then do not call persistent.Reset()
734
  // while the returned Local<T> is still in scope, it will destroy the
735
  // reference to the object.
736
  template <class TypeName>
737
4979929
  static inline v8::Local<TypeName> Default(
738
      v8::Isolate* isolate,
739
      const v8::PersistentBase<TypeName>& persistent) {
740

4979929
    if (persistent.IsWeak()) {
741
3235499
      return PersistentToLocal::Weak(isolate, persistent);
742
    } else {
743
1744430
      return PersistentToLocal::Strong(persistent);
744
    }
745
  }
746
747
  // Unchecked conversion from a non-weak Persistent<T> to Local<T>,
748
  // use with care!
749
  //
750
  // Do not call persistent.Reset() while the returned Local<T> is still in
751
  // scope, it will destroy the reference to the object.
752
  template <class TypeName>
753
18988149
  static inline v8::Local<TypeName> Strong(
754
      const v8::PersistentBase<TypeName>& persistent) {
755
    return *reinterpret_cast<v8::Local<TypeName>*>(
756
18988149
        const_cast<v8::PersistentBase<TypeName>*>(&persistent));
757
  }
758
759
  template <class TypeName>
760
3235498
  static inline v8::Local<TypeName> Weak(
761
      v8::Isolate* isolate,
762
      const v8::PersistentBase<TypeName>& persistent) {
763
3235499
    return v8::Local<TypeName>::New(isolate, persistent);
764
  }
765
};
766
767
}  // namespace node
768
769
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
770
771
#endif  // SRC_UTIL_H_