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: 69 109 63.3 %
Date: 2019-02-01 22:03:38 Branches: 34 108 31.5 %

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

96919
    CHECK_LT(index, length());
308
96919
    return buf_[index];
309
  }
310
311
  const T& operator[](size_t index) const {
312
    CHECK_LT(index, length());
313
    return buf_[index];
314
  }
315
316
123479
  size_t length() const {
317
123479
    return length_;
318
  }
319
320
  // Current maximum capacity of the buffer with which SetLength() can be used
321
  // without first calling AllocateSufficientStorage().
322
755746
  size_t capacity() const {
323
755746
    return IsAllocated() ? capacity_ :
324




755746
                           IsInvalidated() ? 0 : kStackStorageSize;
325
  }
326
327
  // Make sure enough space for `storage` entries is available.
328
  // This method can be called multiple times throughout the lifetime of the
329
  // buffer, but once this has been called Invalidate() cannot be used.
330
  // Content of the buffer in the range [0, length()) is preserved.
331
254544
  void AllocateSufficientStorage(size_t storage) {
332


254544
    CHECK(!IsInvalidated());
333


254544
    if (storage > capacity()) {
334
528
      bool was_allocated = IsAllocated();
335


528
      T* allocated_ptr = was_allocated ? buf_ : nullptr;
336
528
      buf_ = Realloc(allocated_ptr, storage);
337
528
      capacity_ = storage;
338




528
      if (!was_allocated && length_ > 0)
339
        memcpy(buf_, buf_st_, length_ * sizeof(buf_[0]));
340
    }
341
342
254544
    length_ = storage;
343
254544
  }
344
345
256061
  void SetLength(size_t length) {
346
    // capacity() returns how much memory is actually available.
347

256061
    CHECK_LE(length, capacity());
348
256061
    length_ = length;
349
256061
  }
350
351
243487
  void SetLengthAndZeroTerminate(size_t length) {
352
    // capacity() returns how much memory is actually available.
353

243487
    CHECK_LE(length + 1, capacity());
354
243487
    SetLength(length);
355
356
    // T() is 0 for integer types, nullptr for pointers, etc.
357
243487
    buf_[length] = T();
358
243487
  }
359
360
  // Make derefencing this object return nullptr.
361
  // This method can be called multiple times throughout the lifetime of the
362
  // buffer, but once this has been called AllocateSufficientStorage() cannot
363
  // be used.
364
  void Invalidate() {
365
    CHECK(!IsAllocated());
366
    length_ = 0;
367
    buf_ = nullptr;
368
  }
369
370
  // If the buffer is stored in the heap rather than on the stack.
371
7471989
  bool IsAllocated() const {
372




7471989
    return !IsInvalidated() && buf_ != buf_st_;
373
  }
374
375
  // If Invalidate() has been called.
376
14138262
  bool IsInvalidated() const {
377
14138262
    return buf_ == nullptr;
378
  }
379
380
  // Release ownership of the malloc'd buffer.
381
  // Note: This does not free the buffer.
382
  void Release() {
383
    CHECK(IsAllocated());
384
    buf_ = buf_st_;
385
    length_ = 0;
386
    capacity_ = 0;
387
  }
388
389
1801634
  MaybeStackBuffer() : length_(0), capacity_(0), buf_(buf_st_) {
390
    // Default to a zero-length, null-terminated buffer.
391
274643
    buf_[0] = T();
392
263586
  }
393
394
10920
  explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() {
395
10920
    AllocateSufficientStorage(storage);
396
10920
  }
397
398
1877281
  ~MaybeStackBuffer() {
399


1877281
    if (IsAllocated())
400
396971
      free(buf_);
401
1877281
  }
402
403
 private:
404
  size_t length_;
405
  // capacity of the malloc'ed buf_
406
  size_t capacity_;
407
  T* buf_;
408
  T buf_st_[kStackStorageSize];
409
};
410
411
1410850
class Utf8Value : public MaybeStackBuffer<char> {
412
 public:
413
  explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value);
414
};
415
416
489
class TwoByteValue : public MaybeStackBuffer<uint16_t> {
417
 public:
418
  explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
419
};
420
421
33500
class BufferValue : public MaybeStackBuffer<char> {
422
 public:
423
  explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value);
424
};
425
426
#define SPREAD_BUFFER_ARG(val, name)                                          \
427
  CHECK((val)->IsArrayBufferView());                                          \
428
  v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>();      \
429
  v8::ArrayBuffer::Contents name##_c = name->Buffer()->GetContents();         \
430
  const size_t name##_offset = name->ByteOffset();                            \
431
  const size_t name##_length = name->ByteLength();                            \
432
  char* const name##_data =                                                   \
433
      static_cast<char*>(name##_c.Data()) + name##_offset;                    \
434
  if (name##_length > 0)                                                      \
435
    CHECK_NE(name##_data, nullptr);
436
437
// Use this when a variable or parameter is unused in order to explicitly
438
// silence a compiler warning about that.
439
364
template <typename T> inline void USE(T&&) {}
440
441
// Run a function when exiting the current scope.
442
struct OnScopeLeave {
443
  std::function<void()> fn_;
444
445
164
  explicit OnScopeLeave(std::function<void()> fn) : fn_(fn) {}
446
164
  ~OnScopeLeave() { fn_(); }
447
};
448
449
// Simple RAII wrapper for contiguous data that uses malloc()/free().
450
template <typename T>
451
struct MallocedBuffer {
452
  T* data;
453
  size_t size;
454
455
  T* release() {
456
    T* ret = data;
457
    data = nullptr;
458
    return ret;
459
  }
460
461
  void Truncate(size_t new_size) {
462
    CHECK(new_size <= size);
463
    size = new_size;
464
  }
465
466
  inline bool is_empty() const { return data == nullptr; }
467
468
  MallocedBuffer() : data(nullptr), size(0) {}
469
  explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {}
470
  MallocedBuffer(T* data, size_t size) : data(data), size(size) {}
471
  MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) {
472
    other.data = nullptr;
473
  }
474
  MallocedBuffer& operator=(MallocedBuffer&& other) {
475
    this->~MallocedBuffer();
476
    return *new(this) MallocedBuffer(std::move(other));
477
  }
478
  ~MallocedBuffer() {
479
    free(data);
480
  }
481
  MallocedBuffer(const MallocedBuffer&) = delete;
482
  MallocedBuffer& operator=(const MallocedBuffer&) = delete;
483
};
484
485
template <typename T>
486
class NonCopyableMaybe {
487
 public:
488
  NonCopyableMaybe() : empty_(true) {}
489
  explicit NonCopyableMaybe(T&& value)
490
      : empty_(false),
491
        value_(std::move(value)) {}
492
493
  bool IsEmpty() const {
494
    return empty_;
495
  }
496
497
  T&& Release() {
498
    CHECK_EQ(empty_, false);
499
    empty_ = true;
500
    return std::move(value_);
501
  }
502
503
 private:
504
  bool empty_;
505
  T value_;
506
};
507
508
// Test whether some value can be called with ().
509
template <typename T, typename = void>
510
struct is_callable : std::is_function<T> { };
511
512
template <typename T>
513
struct is_callable<T, typename std::enable_if<
514
    std::is_same<decltype(void(&T::operator())), void>::value
515
    >::type> : std::true_type { };
516
517
template <typename T, void (*function)(T*)>
518
struct FunctionDeleter {
519
162
  void operator()(T* pointer) const { function(pointer); }
520
  typedef std::unique_ptr<T, FunctionDeleter> Pointer;
521
};
522
523
template <typename T, void (*function)(T*)>
524
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer;
525
526
std::vector<std::string> SplitString(const std::string& in, char delim);
527
528
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
529
                                           const std::string& str,
530
                                           v8::Isolate* isolate = nullptr);
531
template <typename T, typename test_for_number =
532
    typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type>
533
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
534
                                           const T& number,
535
                                           v8::Isolate* isolate = nullptr);
536
template <typename T>
537
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
538
                                           const std::vector<T>& vec,
539
                                           v8::Isolate* isolate = nullptr);
540
template <typename T, typename U>
541
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context,
542
                                           const std::unordered_map<T, U>& map,
543
                                           v8::Isolate* isolate = nullptr);
544
545
// These macros expects a `Isolate* isolate` and a `Local<Context> context`
546
// to be in the scope.
547
#define READONLY_PROPERTY(obj, name, value)                                    \
548
  do {                                                                         \
549
    obj->DefineOwnProperty(                                                    \
550
           context, FIXED_ONE_BYTE_STRING(isolate, name), value, v8::ReadOnly) \
551
        .FromJust();                                                           \
552
  } while (0)
553
554
#define READONLY_DONT_ENUM_PROPERTY(obj, name, var)                            \
555
  do {                                                                         \
556
    obj->DefineOwnProperty(                                                    \
557
           context,                                                            \
558
           OneByteString(isolate, name),                                       \
559
           var,                                                                \
560
           static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum))    \
561
        .FromJust();                                                           \
562
  } while (0)
563
564
#define READONLY_FALSE_PROPERTY(obj, name)                                     \
565
  READONLY_PROPERTY(obj, name, v8::False(isolate))
566
567
#define READONLY_TRUE_PROPERTY(obj, name)                                      \
568
  READONLY_PROPERTY(obj, name, v8::True(isolate))
569
570
#define READONLY_STRING_PROPERTY(obj, name, str)                               \
571
  READONLY_PROPERTY(obj, name, ToV8Value(context, str).ToLocalChecked())
572
573
// Variation on NODE_DEFINE_CONSTANT that sets a String value.
574
#define NODE_DEFINE_STRING_CONSTANT(target, name, constant)                    \
575
  do {                                                                         \
576
    v8::Isolate* isolate = target->GetIsolate();                               \
577
    v8::Local<v8::String> constant_name =                                      \
578
        v8::String::NewFromUtf8(isolate, name, v8::NewStringType::kNormal)     \
579
            .ToLocalChecked();                                                 \
580
    v8::Local<v8::String> constant_value =                                     \
581
        v8::String::NewFromUtf8(isolate, constant, v8::NewStringType::kNormal) \
582
            .ToLocalChecked();                                                 \
583
    v8::PropertyAttribute constant_attributes =                                \
584
        static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete);     \
585
    target                                                                     \
586
        ->DefineOwnProperty(isolate->GetCurrentContext(),                      \
587
                            constant_name,                                     \
588
                            constant_value,                                    \
589
                            constant_attributes)                               \
590
        .FromJust();                                                           \
591
  } while (0)
592
593
enum Endianness {
594
  kLittleEndian,  // _Not_ LITTLE_ENDIAN, clashes with endian.h.
595
  kBigEndian
596
};
597
598
150
inline enum Endianness GetEndianness() {
599
  // Constant-folded by the compiler.
600
  const union {
601
    uint8_t u8[2];
602
    uint16_t u16;
603
150
  } u = {{1, 0}};
604
150
  return u.u16 == 1 ? kLittleEndian : kBigEndian;
605
}
606
607
inline bool IsLittleEndian() {
608
  return GetEndianness() == kLittleEndian;
609
}
610
611
150
inline bool IsBigEndian() {
612
150
  return GetEndianness() == kBigEndian;
613
}
614
615
template <typename T, size_t N>
616
44985
constexpr size_t arraysize(const T (&)[N]) {
617
44985
  return N;
618
}
619
620
// Round up a to the next highest multiple of b.
621
template <typename T>
622
530
constexpr T RoundUp(T a, T b) {
623
530
  return a % b != 0 ? a + b - (a % b) : a;
624
}
625
626
#ifdef __GNUC__
627
#define MUST_USE_RESULT __attribute__((warn_unused_result))
628
#else
629
#define MUST_USE_RESULT
630
#endif
631
632
137
class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> {
633
 public:
634
  inline explicit SlicedArguments(
635
      const v8::FunctionCallbackInfo<v8::Value>& args, size_t start = 0);
636
};
637
638
}  // namespace node
639
640
#endif  // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
641
642
#endif  // SRC_UTIL_H_