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 "v8.h" |
28 |
|
|
|
29 |
|
|
#include "node.h" |
30 |
|
|
#include "node_exit_code.h" |
31 |
|
|
|
32 |
|
|
#include <climits> |
33 |
|
|
#include <cstddef> |
34 |
|
|
#include <cstdio> |
35 |
|
|
#include <cstdlib> |
36 |
|
|
#include <cstring> |
37 |
|
|
|
38 |
|
|
#include <array> |
39 |
|
|
#include <limits> |
40 |
|
|
#include <memory> |
41 |
|
|
#include <string> |
42 |
|
|
#include <string_view> |
43 |
|
|
#include <type_traits> |
44 |
|
|
#include <set> |
45 |
|
|
#include <unordered_map> |
46 |
|
|
#include <utility> |
47 |
|
|
#include <vector> |
48 |
|
|
|
49 |
|
|
#ifdef __GNUC__ |
50 |
|
|
#define MUST_USE_RESULT __attribute__((warn_unused_result)) |
51 |
|
|
#else |
52 |
|
|
#define MUST_USE_RESULT |
53 |
|
|
#endif |
54 |
|
|
|
55 |
|
|
namespace node { |
56 |
|
|
|
57 |
|
|
// Maybe remove kPathSeparator when cpp17 is ready |
58 |
|
|
#ifdef _WIN32 |
59 |
|
|
constexpr char kPathSeparator = '\\'; |
60 |
|
|
/* MAX_PATH is in characters, not bytes. Make sure we have enough headroom. */ |
61 |
|
|
#define PATH_MAX_BYTES (MAX_PATH * 4) |
62 |
|
|
#else |
63 |
|
|
constexpr char kPathSeparator = '/'; |
64 |
|
|
#define PATH_MAX_BYTES (PATH_MAX) |
65 |
|
|
#endif |
66 |
|
|
|
67 |
|
|
// These should be used in our code as opposed to the native |
68 |
|
|
// versions as they abstract out some platform and or |
69 |
|
|
// compiler version specific functionality |
70 |
|
|
// malloc(0) and realloc(ptr, 0) have implementation-defined behavior in |
71 |
|
|
// that the standard allows them to either return a unique pointer or a |
72 |
|
|
// nullptr for zero-sized allocation requests. Normalize by always using |
73 |
|
|
// a nullptr. |
74 |
|
|
template <typename T> |
75 |
|
|
inline T* UncheckedRealloc(T* pointer, size_t n); |
76 |
|
|
template <typename T> |
77 |
|
|
inline T* UncheckedMalloc(size_t n); |
78 |
|
|
template <typename T> |
79 |
|
|
inline T* UncheckedCalloc(size_t n); |
80 |
|
|
|
81 |
|
|
// Same things, but aborts immediately instead of returning nullptr when |
82 |
|
|
// no memory is available. |
83 |
|
|
template <typename T> |
84 |
|
|
inline T* Realloc(T* pointer, size_t n); |
85 |
|
|
template <typename T> |
86 |
|
|
inline T* Malloc(size_t n); |
87 |
|
|
template <typename T> |
88 |
|
|
inline T* Calloc(size_t n); |
89 |
|
|
|
90 |
|
|
inline char* Malloc(size_t n); |
91 |
|
|
inline char* Calloc(size_t n); |
92 |
|
|
inline char* UncheckedMalloc(size_t n); |
93 |
|
|
inline char* UncheckedCalloc(size_t n); |
94 |
|
|
|
95 |
|
|
template <typename T> |
96 |
|
|
inline T MultiplyWithOverflowCheck(T a, T b); |
97 |
|
|
|
98 |
|
|
namespace per_process { |
99 |
|
|
// Tells whether the per-process V8::Initialize() is called and |
100 |
|
|
// if it is safe to call v8::Isolate::TryGetCurrent(). |
101 |
|
|
extern bool v8_initialized; |
102 |
|
|
} // namespace per_process |
103 |
|
|
|
104 |
|
|
// Used by the allocation functions when allocation fails. |
105 |
|
|
// Thin wrapper around v8::Isolate::LowMemoryNotification() that checks |
106 |
|
|
// whether V8 is initialized. |
107 |
|
|
void LowMemoryNotification(); |
108 |
|
|
|
109 |
|
|
// The reason that Assert() takes a struct argument instead of individual |
110 |
|
|
// const char*s is to ease instruction cache pressure in calls from CHECK. |
111 |
|
|
struct AssertionInfo { |
112 |
|
|
const char* file_line; // filename:line |
113 |
|
|
const char* message; |
114 |
|
|
const char* function; |
115 |
|
|
}; |
116 |
|
|
[[noreturn]] void NODE_EXTERN_PRIVATE Assert(const AssertionInfo& info); |
117 |
|
|
[[noreturn]] void NODE_EXTERN_PRIVATE Abort(); |
118 |
|
|
void DumpBacktrace(FILE* fp); |
119 |
|
|
|
120 |
|
|
// Windows 8+ does not like abort() in Release mode |
121 |
|
|
#ifdef _WIN32 |
122 |
|
|
#define ABORT_NO_BACKTRACE() _exit(static_cast<int>(node::ExitCode::kAbort)) |
123 |
|
|
#else |
124 |
|
|
#define ABORT_NO_BACKTRACE() abort() |
125 |
|
|
#endif |
126 |
|
|
|
127 |
|
|
#define ABORT() node::Abort() |
128 |
|
|
|
129 |
|
|
#define ERROR_AND_ABORT(expr) \ |
130 |
|
|
do { \ |
131 |
|
|
/* Make sure that this struct does not end up in inline code, but */ \ |
132 |
|
|
/* rather in a read-only data section when modifying this code. */ \ |
133 |
|
|
static const node::AssertionInfo args = { \ |
134 |
|
|
__FILE__ ":" STRINGIFY(__LINE__), #expr, PRETTY_FUNCTION_NAME \ |
135 |
|
|
}; \ |
136 |
|
|
node::Assert(args); \ |
137 |
|
|
} while (0) |
138 |
|
|
|
139 |
|
|
#ifdef __GNUC__ |
140 |
|
|
#define LIKELY(expr) __builtin_expect(!!(expr), 1) |
141 |
|
|
#define UNLIKELY(expr) __builtin_expect(!!(expr), 0) |
142 |
|
|
#define PRETTY_FUNCTION_NAME __PRETTY_FUNCTION__ |
143 |
|
|
#else |
144 |
|
|
#define LIKELY(expr) expr |
145 |
|
|
#define UNLIKELY(expr) expr |
146 |
|
|
#define PRETTY_FUNCTION_NAME "" |
147 |
|
|
#endif |
148 |
|
|
|
149 |
|
|
#define STRINGIFY_(x) #x |
150 |
|
|
#define STRINGIFY(x) STRINGIFY_(x) |
151 |
|
|
|
152 |
|
|
#define CHECK(expr) \ |
153 |
|
|
do { \ |
154 |
|
|
if (UNLIKELY(!(expr))) { \ |
155 |
|
|
ERROR_AND_ABORT(expr); \ |
156 |
|
|
} \ |
157 |
|
|
} while (0) |
158 |
|
|
|
159 |
|
|
#define CHECK_EQ(a, b) CHECK((a) == (b)) |
160 |
|
|
#define CHECK_GE(a, b) CHECK((a) >= (b)) |
161 |
|
|
#define CHECK_GT(a, b) CHECK((a) > (b)) |
162 |
|
|
#define CHECK_LE(a, b) CHECK((a) <= (b)) |
163 |
|
|
#define CHECK_LT(a, b) CHECK((a) < (b)) |
164 |
|
|
#define CHECK_NE(a, b) CHECK((a) != (b)) |
165 |
|
|
#define CHECK_NULL(val) CHECK((val) == nullptr) |
166 |
|
|
#define CHECK_NOT_NULL(val) CHECK((val) != nullptr) |
167 |
|
|
#define CHECK_IMPLIES(a, b) CHECK(!(a) || (b)) |
168 |
|
|
|
169 |
|
|
#ifdef DEBUG |
170 |
|
|
#define DCHECK(expr) CHECK(expr) |
171 |
|
|
#define DCHECK_EQ(a, b) CHECK((a) == (b)) |
172 |
|
|
#define DCHECK_GE(a, b) CHECK((a) >= (b)) |
173 |
|
|
#define DCHECK_GT(a, b) CHECK((a) > (b)) |
174 |
|
|
#define DCHECK_LE(a, b) CHECK((a) <= (b)) |
175 |
|
|
#define DCHECK_LT(a, b) CHECK((a) < (b)) |
176 |
|
|
#define DCHECK_NE(a, b) CHECK((a) != (b)) |
177 |
|
|
#define DCHECK_NULL(val) CHECK((val) == nullptr) |
178 |
|
|
#define DCHECK_NOT_NULL(val) CHECK((val) != nullptr) |
179 |
|
|
#define DCHECK_IMPLIES(a, b) CHECK(!(a) || (b)) |
180 |
|
|
#else |
181 |
|
|
#define DCHECK(expr) |
182 |
|
|
#define DCHECK_EQ(a, b) |
183 |
|
|
#define DCHECK_GE(a, b) |
184 |
|
|
#define DCHECK_GT(a, b) |
185 |
|
|
#define DCHECK_LE(a, b) |
186 |
|
|
#define DCHECK_LT(a, b) |
187 |
|
|
#define DCHECK_NE(a, b) |
188 |
|
|
#define DCHECK_NULL(val) |
189 |
|
|
#define DCHECK_NOT_NULL(val) |
190 |
|
|
#define DCHECK_IMPLIES(a, b) |
191 |
|
|
#endif |
192 |
|
|
|
193 |
|
|
|
194 |
|
|
#define UNREACHABLE(...) \ |
195 |
|
|
ERROR_AND_ABORT("Unreachable code reached" __VA_OPT__(": ") __VA_ARGS__) |
196 |
|
|
|
197 |
|
|
// ECMA262 20.1.2.6 Number.MAX_SAFE_INTEGER (2^53-1) |
198 |
|
|
constexpr int64_t kMaxSafeJsInteger = 9007199254740991; |
199 |
|
|
|
200 |
|
|
inline bool IsSafeJsInt(v8::Local<v8::Value> v); |
201 |
|
|
|
202 |
|
|
// TAILQ-style intrusive list node. |
203 |
|
|
template <typename T> |
204 |
|
|
class ListNode; |
205 |
|
|
|
206 |
|
|
// TAILQ-style intrusive list head. |
207 |
|
|
template <typename T, ListNode<T> (T::*M)> |
208 |
|
|
class ListHead; |
209 |
|
|
|
210 |
|
|
template <typename T> |
211 |
|
|
class ListNode { |
212 |
|
|
public: |
213 |
|
|
inline ListNode(); |
214 |
|
|
inline ~ListNode(); |
215 |
|
|
inline void Remove(); |
216 |
|
|
inline bool IsEmpty() const; |
217 |
|
|
|
218 |
|
|
ListNode(const ListNode&) = delete; |
219 |
|
|
ListNode& operator=(const ListNode&) = delete; |
220 |
|
|
|
221 |
|
|
private: |
222 |
|
|
template <typename U, ListNode<U> (U::*M)> friend class ListHead; |
223 |
|
|
friend int GenDebugSymbols(); |
224 |
|
|
ListNode* prev_; |
225 |
|
|
ListNode* next_; |
226 |
|
|
}; |
227 |
|
|
|
228 |
|
|
template <typename T, ListNode<T> (T::*M)> |
229 |
|
|
class ListHead { |
230 |
|
|
public: |
231 |
|
|
class Iterator { |
232 |
|
|
public: |
233 |
|
|
inline T* operator*() const; |
234 |
|
|
inline const Iterator& operator++(); |
235 |
|
|
inline bool operator!=(const Iterator& that) const; |
236 |
|
|
|
237 |
|
|
private: |
238 |
|
|
friend class ListHead; |
239 |
|
|
inline explicit Iterator(ListNode<T>* node); |
240 |
|
|
ListNode<T>* node_; |
241 |
|
|
}; |
242 |
|
|
|
243 |
|
25725 |
inline ListHead() = default; |
244 |
|
|
inline ~ListHead(); |
245 |
|
|
inline void PushBack(T* element); |
246 |
|
|
inline void PushFront(T* element); |
247 |
|
|
inline bool IsEmpty() const; |
248 |
|
|
inline T* PopFront(); |
249 |
|
|
inline Iterator begin() const; |
250 |
|
|
inline Iterator end() const; |
251 |
|
|
|
252 |
|
|
ListHead(const ListHead&) = delete; |
253 |
|
|
ListHead& operator=(const ListHead&) = delete; |
254 |
|
|
|
255 |
|
|
private: |
256 |
|
|
friend int GenDebugSymbols(); |
257 |
|
|
ListNode<T> head_; |
258 |
|
|
}; |
259 |
|
|
|
260 |
|
|
// The helper is for doing safe downcasts from base types to derived types. |
261 |
|
|
template <typename Inner, typename Outer> |
262 |
|
|
class ContainerOfHelper { |
263 |
|
|
public: |
264 |
|
|
inline ContainerOfHelper(Inner Outer::*field, Inner* pointer); |
265 |
|
|
template <typename TypeName> |
266 |
|
|
inline operator TypeName*() const; |
267 |
|
|
private: |
268 |
|
|
Outer* const pointer_; |
269 |
|
|
}; |
270 |
|
|
|
271 |
|
|
// Calculate the address of the outer (i.e. embedding) struct from |
272 |
|
|
// the interior pointer to a data member. |
273 |
|
|
template <typename Inner, typename Outer> |
274 |
|
|
constexpr ContainerOfHelper<Inner, Outer> ContainerOf(Inner Outer::*field, |
275 |
|
|
Inner* pointer); |
276 |
|
|
|
277 |
|
|
class KVStore { |
278 |
|
|
public: |
279 |
|
6689 |
KVStore() = default; |
280 |
|
11986 |
virtual ~KVStore() = default; |
281 |
|
|
KVStore(const KVStore&) = delete; |
282 |
|
|
KVStore& operator=(const KVStore&) = delete; |
283 |
|
|
KVStore(KVStore&&) = delete; |
284 |
|
|
KVStore& operator=(KVStore&&) = delete; |
285 |
|
|
|
286 |
|
|
virtual v8::MaybeLocal<v8::String> Get(v8::Isolate* isolate, |
287 |
|
|
v8::Local<v8::String> key) const = 0; |
288 |
|
|
virtual v8::Maybe<std::string> Get(const char* key) const = 0; |
289 |
|
|
virtual void Set(v8::Isolate* isolate, |
290 |
|
|
v8::Local<v8::String> key, |
291 |
|
|
v8::Local<v8::String> value) = 0; |
292 |
|
|
virtual int32_t Query(v8::Isolate* isolate, |
293 |
|
|
v8::Local<v8::String> key) const = 0; |
294 |
|
|
virtual int32_t Query(const char* key) const = 0; |
295 |
|
|
virtual void Delete(v8::Isolate* isolate, v8::Local<v8::String> key) = 0; |
296 |
|
|
virtual v8::Local<v8::Array> Enumerate(v8::Isolate* isolate) const = 0; |
297 |
|
|
|
298 |
|
|
virtual std::shared_ptr<KVStore> Clone(v8::Isolate* isolate) const; |
299 |
|
|
virtual v8::Maybe<bool> AssignFromObject(v8::Local<v8::Context> context, |
300 |
|
|
v8::Local<v8::Object> entries); |
301 |
|
|
|
302 |
|
|
static std::shared_ptr<KVStore> CreateMapKVStore(); |
303 |
|
|
}; |
304 |
|
|
|
305 |
|
|
// Convenience wrapper around v8::String::NewFromOneByte(). |
306 |
|
|
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate, |
307 |
|
|
const char* data, |
308 |
|
|
int length = -1); |
309 |
|
|
|
310 |
|
|
// For the people that compile with -funsigned-char. |
311 |
|
|
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate, |
312 |
|
|
const signed char* data, |
313 |
|
|
int length = -1); |
314 |
|
|
|
315 |
|
|
inline v8::Local<v8::String> OneByteString(v8::Isolate* isolate, |
316 |
|
|
const unsigned char* data, |
317 |
|
|
int length = -1); |
318 |
|
|
|
319 |
|
|
// Used to be a macro, hence the uppercase name. |
320 |
|
|
template <int N> |
321 |
|
6665553 |
inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING( |
322 |
|
|
v8::Isolate* isolate, |
323 |
|
|
const char(&data)[N]) { |
324 |
|
6665553 |
return OneByteString(isolate, data, N - 1); |
325 |
|
|
} |
326 |
|
|
|
327 |
|
|
template <std::size_t N> |
328 |
|
716 |
inline v8::Local<v8::String> FIXED_ONE_BYTE_STRING( |
329 |
|
|
v8::Isolate* isolate, |
330 |
|
|
const std::array<char, N>& arr) { |
331 |
|
716 |
return OneByteString(isolate, arr.data(), N - 1); |
332 |
|
|
} |
333 |
|
|
|
334 |
|
|
|
335 |
|
|
|
336 |
|
|
// Swaps bytes in place. nbytes is the number of bytes to swap and must be a |
337 |
|
|
// multiple of the word size (checked by function). |
338 |
|
|
inline void SwapBytes16(char* data, size_t nbytes); |
339 |
|
|
inline void SwapBytes32(char* data, size_t nbytes); |
340 |
|
|
inline void SwapBytes64(char* data, size_t nbytes); |
341 |
|
|
|
342 |
|
|
// tolower() is locale-sensitive. Use ToLower() instead. |
343 |
|
|
inline char ToLower(char c); |
344 |
|
|
inline std::string ToLower(const std::string& in); |
345 |
|
|
|
346 |
|
|
// toupper() is locale-sensitive. Use ToUpper() instead. |
347 |
|
|
inline char ToUpper(char c); |
348 |
|
|
inline std::string ToUpper(const std::string& in); |
349 |
|
|
|
350 |
|
|
// strcasecmp() is locale-sensitive. Use StringEqualNoCase() instead. |
351 |
|
|
inline bool StringEqualNoCase(const char* a, const char* b); |
352 |
|
|
|
353 |
|
|
// strncasecmp() is locale-sensitive. Use StringEqualNoCaseN() instead. |
354 |
|
|
inline bool StringEqualNoCaseN(const char* a, const char* b, size_t length); |
355 |
|
|
|
356 |
|
|
template <typename T, size_t N> |
357 |
|
11809061 |
constexpr size_t arraysize(const T (&)[N]) { |
358 |
|
11809061 |
return N; |
359 |
|
|
} |
360 |
|
|
|
361 |
|
|
template <typename T, size_t N> |
362 |
|
|
constexpr size_t strsize(const T (&)[N]) { |
363 |
|
|
return N - 1; |
364 |
|
|
} |
365 |
|
|
|
366 |
|
|
// Allocates an array of member type T. For up to kStackStorageSize items, |
367 |
|
|
// the stack is used, otherwise malloc(). |
368 |
|
|
template <typename T, size_t kStackStorageSize = 1024> |
369 |
|
|
class MaybeStackBuffer { |
370 |
|
|
public: |
371 |
|
6090 |
const T* out() const { |
372 |
|
6090 |
return buf_; |
373 |
|
|
} |
374 |
|
|
|
375 |
|
6333388 |
T* out() { |
376 |
|
6333388 |
return buf_; |
377 |
|
|
} |
378 |
|
|
|
379 |
|
|
// operator* for compatibility with `v8::String::(Utf8)Value` |
380 |
|
9580254 |
T* operator*() { |
381 |
|
9580254 |
return buf_; |
382 |
|
|
} |
383 |
|
|
|
384 |
|
30480 |
const T* operator*() const { |
385 |
|
30480 |
return buf_; |
386 |
|
|
} |
387 |
|
|
|
388 |
|
2722453 |
T& operator[](size_t index) { |
389 |
✗✓ |
2722453 |
CHECK_LT(index, length()); |
390 |
|
2722453 |
return buf_[index]; |
391 |
|
|
} |
392 |
|
|
|
393 |
|
11200 |
const T& operator[](size_t index) const { |
394 |
✗✓ |
11200 |
CHECK_LT(index, length()); |
395 |
|
11200 |
return buf_[index]; |
396 |
|
|
} |
397 |
|
|
|
398 |
|
10649089 |
size_t length() const { |
399 |
|
10649089 |
return length_; |
400 |
|
|
} |
401 |
|
|
|
402 |
|
|
// Current maximum capacity of the buffer with which SetLength() can be used |
403 |
|
|
// without first calling AllocateSufficientStorage(). |
404 |
|
19044786 |
size_t capacity() const { |
405 |
|
19044786 |
return capacity_; |
406 |
|
|
} |
407 |
|
|
|
408 |
|
|
// Make sure enough space for `storage` entries is available. |
409 |
|
|
// This method can be called multiple times throughout the lifetime of the |
410 |
|
|
// buffer, but once this has been called Invalidate() cannot be used. |
411 |
|
|
// Content of the buffer in the range [0, length()) is preserved. |
412 |
|
6683866 |
void AllocateSufficientStorage(size_t storage) { |
413 |
✗✓ |
6683866 |
CHECK(!IsInvalidated()); |
414 |
✓✓ |
6683866 |
if (storage > capacity()) { |
415 |
|
299930 |
bool was_allocated = IsAllocated(); |
416 |
✓✓ |
299930 |
T* allocated_ptr = was_allocated ? buf_ : nullptr; |
417 |
|
299930 |
buf_ = Realloc(allocated_ptr, storage); |
418 |
|
299930 |
capacity_ = storage; |
419 |
✓✓✓✓
|
299930 |
if (!was_allocated && length_ > 0) |
420 |
|
4 |
memcpy(buf_, buf_st_, length_ * sizeof(buf_[0])); |
421 |
|
|
} |
422 |
|
|
|
423 |
|
6683866 |
length_ = storage; |
424 |
|
6683866 |
} |
425 |
|
|
|
426 |
|
6187658 |
void SetLength(size_t length) { |
427 |
|
|
// capacity() returns how much memory is actually available. |
428 |
✗✓ |
6187658 |
CHECK_LE(length, capacity()); |
429 |
|
6187658 |
length_ = length; |
430 |
|
6187658 |
} |
431 |
|
|
|
432 |
|
9183515 |
void SetLengthAndZeroTerminate(size_t length) { |
433 |
|
|
// capacity() returns how much memory is actually available. |
434 |
✗✓ |
9183515 |
CHECK_LE(length + 1, capacity()); |
435 |
|
9183515 |
SetLength(length); |
436 |
|
|
|
437 |
|
|
// T() is 0 for integer types, nullptr for pointers, etc. |
438 |
|
9183515 |
buf_[length] = T(); |
439 |
|
9183515 |
} |
440 |
|
|
|
441 |
|
|
// Make dereferencing this object return nullptr. |
442 |
|
|
// This method can be called multiple times throughout the lifetime of the |
443 |
|
|
// buffer, but once this has been called AllocateSufficientStorage() cannot |
444 |
|
|
// be used. |
445 |
|
2 |
void Invalidate() { |
446 |
✗✓ |
2 |
CHECK(!IsAllocated()); |
447 |
|
2 |
capacity_ = 0; |
448 |
|
2 |
length_ = 0; |
449 |
|
2 |
buf_ = nullptr; |
450 |
|
2 |
} |
451 |
|
|
|
452 |
|
|
// If the buffer is stored in the heap rather than on the stack. |
453 |
|
9112938 |
bool IsAllocated() const { |
454 |
✓✓✓✓
|
9112938 |
return !IsInvalidated() && buf_ != buf_st_; |
455 |
|
|
} |
456 |
|
|
|
457 |
|
|
// If Invalidate() has been called. |
458 |
|
16193860 |
bool IsInvalidated() const { |
459 |
|
16193860 |
return buf_ == nullptr; |
460 |
|
|
} |
461 |
|
|
|
462 |
|
|
// Release ownership of the malloc'd buffer. |
463 |
|
|
// Note: This does not free the buffer. |
464 |
|
8 |
void Release() { |
465 |
✗✓ |
8 |
CHECK(IsAllocated()); |
466 |
|
8 |
buf_ = buf_st_; |
467 |
|
8 |
length_ = 0; |
468 |
|
8 |
capacity_ = arraysize(buf_st_); |
469 |
|
8 |
} |
470 |
|
|
|
471 |
|
8353837 |
MaybeStackBuffer() |
472 |
✓✓ |
134551821 |
: length_(0), capacity_(arraysize(buf_st_)), buf_(buf_st_) { |
473 |
|
|
// Default to a zero-length, null-terminated buffer. |
474 |
|
8353837 |
buf_[0] = T(); |
475 |
|
8353837 |
} |
476 |
|
|
|
477 |
|
439872 |
explicit MaybeStackBuffer(size_t storage) : MaybeStackBuffer() { |
478 |
|
439872 |
AllocateSufficientStorage(storage); |
479 |
|
439872 |
} |
480 |
|
|
|
481 |
|
8812099 |
~MaybeStackBuffer() { |
482 |
✓✓ |
8812099 |
if (IsAllocated()) |
483 |
|
300758 |
free(buf_); |
484 |
|
8812099 |
} |
485 |
|
|
|
486 |
|
|
private: |
487 |
|
|
size_t length_; |
488 |
|
|
// capacity of the malloc'ed buf_ |
489 |
|
|
size_t capacity_; |
490 |
|
|
T* buf_; |
491 |
|
|
T buf_st_[kStackStorageSize]; |
492 |
|
|
}; |
493 |
|
|
|
494 |
|
|
// Provides access to an ArrayBufferView's storage, either the original, |
495 |
|
|
// or for small data, a copy of it. This object's lifetime is bound to the |
496 |
|
|
// original ArrayBufferView's lifetime. |
497 |
|
|
template <typename T, size_t kStackStorageSize = 64> |
498 |
|
|
class ArrayBufferViewContents { |
499 |
|
|
public: |
500 |
|
1254 |
ArrayBufferViewContents() = default; |
501 |
|
|
|
502 |
|
|
ArrayBufferViewContents(const ArrayBufferViewContents&) = delete; |
503 |
|
|
void operator=(const ArrayBufferViewContents&) = delete; |
504 |
|
|
|
505 |
|
|
explicit inline ArrayBufferViewContents(v8::Local<v8::Value> value); |
506 |
|
|
explicit inline ArrayBufferViewContents(v8::Local<v8::Object> value); |
507 |
|
|
explicit inline ArrayBufferViewContents(v8::Local<v8::ArrayBufferView> abv); |
508 |
|
|
inline void Read(v8::Local<v8::ArrayBufferView> abv); |
509 |
|
|
inline void ReadValue(v8::Local<v8::Value> buf); |
510 |
|
|
|
511 |
|
183614 |
inline const T* data() const { return data_; } |
512 |
|
466097 |
inline size_t length() const { return length_; } |
513 |
|
|
|
514 |
|
|
private: |
515 |
|
|
// Declaring operator new and delete as deleted is not spec compliant. |
516 |
|
|
// Therefore, declare them private instead to disable dynamic alloc. |
517 |
|
|
void* operator new(size_t size); |
518 |
|
|
void* operator new[](size_t size); |
519 |
|
|
void operator delete(void*, size_t); |
520 |
|
|
void operator delete[](void*, size_t); |
521 |
|
|
|
522 |
|
|
T stack_storage_[kStackStorageSize]; |
523 |
|
|
T* data_ = nullptr; |
524 |
|
|
size_t length_ = 0; |
525 |
|
|
}; |
526 |
|
|
|
527 |
|
|
class Utf8Value : public MaybeStackBuffer<char> { |
528 |
|
|
public: |
529 |
|
|
explicit Utf8Value(v8::Isolate* isolate, v8::Local<v8::Value> value); |
530 |
|
|
|
531 |
|
1129 |
inline std::string ToString() const { return std::string(out(), length()); } |
532 |
|
|
|
533 |
|
4961 |
inline bool operator==(const char* a) const { |
534 |
|
4961 |
return strcmp(out(), a) == 0; |
535 |
|
|
} |
536 |
|
|
}; |
537 |
|
|
|
538 |
|
|
class TwoByteValue : public MaybeStackBuffer<uint16_t> { |
539 |
|
|
public: |
540 |
|
|
explicit TwoByteValue(v8::Isolate* isolate, v8::Local<v8::Value> value); |
541 |
|
|
}; |
542 |
|
|
|
543 |
|
|
class BufferValue : public MaybeStackBuffer<char> { |
544 |
|
|
public: |
545 |
|
|
explicit BufferValue(v8::Isolate* isolate, v8::Local<v8::Value> value); |
546 |
|
|
|
547 |
|
|
inline std::string ToString() const { return std::string(out(), length()); } |
548 |
|
|
}; |
549 |
|
|
|
550 |
|
|
#define SPREAD_BUFFER_ARG(val, name) \ |
551 |
|
|
CHECK((val)->IsArrayBufferView()); \ |
552 |
|
|
v8::Local<v8::ArrayBufferView> name = (val).As<v8::ArrayBufferView>(); \ |
553 |
|
|
const size_t name##_offset = name->ByteOffset(); \ |
554 |
|
|
const size_t name##_length = name->ByteLength(); \ |
555 |
|
|
char* const name##_data = \ |
556 |
|
|
static_cast<char*>(name->Buffer()->Data()) + name##_offset; \ |
557 |
|
|
if (name##_length > 0) CHECK_NE(name##_data, nullptr); |
558 |
|
|
|
559 |
|
|
// Use this when a variable or parameter is unused in order to explicitly |
560 |
|
|
// silence a compiler warning about that. |
561 |
|
5269716 |
template <typename T> inline void USE(T&&) {} |
562 |
|
|
|
563 |
|
|
template <typename Fn> |
564 |
|
|
struct OnScopeLeaveImpl { |
565 |
|
|
Fn fn_; |
566 |
|
|
bool active_; |
567 |
|
|
|
568 |
|
3592917 |
explicit OnScopeLeaveImpl(Fn&& fn) : fn_(std::move(fn)), active_(true) {} |
569 |
✓✗ |
1812504 |
~OnScopeLeaveImpl() { if (active_) fn_(); } |
570 |
|
|
|
571 |
|
|
OnScopeLeaveImpl(const OnScopeLeaveImpl& other) = delete; |
572 |
|
|
OnScopeLeaveImpl& operator=(const OnScopeLeaveImpl& other) = delete; |
573 |
|
|
OnScopeLeaveImpl(OnScopeLeaveImpl&& other) |
574 |
|
|
: fn_(std::move(other.fn_)), active_(other.active_) { |
575 |
|
|
other.active_ = false; |
576 |
|
|
} |
577 |
|
|
OnScopeLeaveImpl& operator=(OnScopeLeaveImpl&& other) { |
578 |
|
|
if (this == &other) return *this; |
579 |
|
|
this->~OnScopeLeave(); |
580 |
|
|
new (this)OnScopeLeaveImpl(std::move(other)); |
581 |
|
|
return *this; |
582 |
|
|
} |
583 |
|
|
}; |
584 |
|
|
|
585 |
|
|
// Run a function when exiting the current scope. Used like this: |
586 |
|
|
// auto on_scope_leave = OnScopeLeave([&] { |
587 |
|
|
// // ... run some code ... |
588 |
|
|
// }); |
589 |
|
|
template <typename Fn> |
590 |
|
3592917 |
inline MUST_USE_RESULT OnScopeLeaveImpl<Fn> OnScopeLeave(Fn&& fn) { |
591 |
|
3592917 |
return OnScopeLeaveImpl<Fn>{std::move(fn)}; |
592 |
|
|
} |
593 |
|
|
|
594 |
|
|
// Simple RAII wrapper for contiguous data that uses malloc()/free(). |
595 |
|
|
template <typename T> |
596 |
|
|
struct MallocedBuffer { |
597 |
|
|
T* data; |
598 |
|
|
size_t size; |
599 |
|
|
|
600 |
|
|
T* release() { |
601 |
|
|
T* ret = data; |
602 |
|
|
data = nullptr; |
603 |
|
|
return ret; |
604 |
|
|
} |
605 |
|
|
|
606 |
|
|
void Truncate(size_t new_size) { |
607 |
|
|
CHECK(new_size <= size); |
608 |
|
|
size = new_size; |
609 |
|
|
} |
610 |
|
|
|
611 |
|
|
void Realloc(size_t new_size) { |
612 |
|
|
Truncate(new_size); |
613 |
|
|
data = UncheckedRealloc(data, new_size); |
614 |
|
|
} |
615 |
|
|
|
616 |
|
80173 |
inline bool is_empty() const { return data == nullptr; } |
617 |
|
|
|
618 |
|
116562 |
MallocedBuffer() : data(nullptr), size(0) {} |
619 |
|
1014 |
explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {} |
620 |
|
80197 |
MallocedBuffer(T* data, size_t size) : data(data), size(size) {} |
621 |
|
196722 |
MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) { |
622 |
|
196722 |
other.data = nullptr; |
623 |
|
196722 |
} |
624 |
|
80221 |
MallocedBuffer& operator=(MallocedBuffer&& other) { |
625 |
|
80221 |
this->~MallocedBuffer(); |
626 |
|
80221 |
return *new(this) MallocedBuffer(std::move(other)); |
627 |
|
|
} |
628 |
|
394467 |
~MallocedBuffer() { |
629 |
|
394467 |
free(data); |
630 |
|
394467 |
} |
631 |
|
|
MallocedBuffer(const MallocedBuffer&) = delete; |
632 |
|
|
MallocedBuffer& operator=(const MallocedBuffer&) = delete; |
633 |
|
|
}; |
634 |
|
|
|
635 |
|
|
template <typename T> |
636 |
|
|
class NonCopyableMaybe { |
637 |
|
|
public: |
638 |
|
5073 |
NonCopyableMaybe() : empty_(true) {} |
639 |
|
4382 |
explicit NonCopyableMaybe(T&& value) |
640 |
|
|
: empty_(false), |
641 |
|
8764 |
value_(std::move(value)) {} |
642 |
|
|
|
643 |
|
8702 |
bool IsEmpty() const { |
644 |
|
8702 |
return empty_; |
645 |
|
|
} |
646 |
|
|
|
647 |
|
1541 |
const T* get() const { |
648 |
✓✓ |
1541 |
return empty_ ? nullptr : &value_; |
649 |
|
|
} |
650 |
|
|
|
651 |
|
26 |
const T* operator->() const { |
652 |
✗✓ |
26 |
CHECK(!empty_); |
653 |
|
26 |
return &value_; |
654 |
|
|
} |
655 |
|
|
|
656 |
|
4285 |
T&& Release() { |
657 |
✗✓ |
4285 |
CHECK_EQ(empty_, false); |
658 |
|
4285 |
empty_ = true; |
659 |
|
4285 |
return std::move(value_); |
660 |
|
|
} |
661 |
|
|
|
662 |
|
|
private: |
663 |
|
|
bool empty_; |
664 |
|
|
T value_; |
665 |
|
|
}; |
666 |
|
|
|
667 |
|
|
// Test whether some value can be called with (). |
668 |
|
|
template <typename T, typename = void> |
669 |
|
|
struct is_callable : std::is_function<T> { }; |
670 |
|
|
|
671 |
|
|
template <typename T> |
672 |
|
|
struct is_callable<T, typename std::enable_if< |
673 |
|
|
std::is_same<decltype(void(&T::operator())), void>::value |
674 |
|
|
>::type> : std::true_type { }; |
675 |
|
|
|
676 |
|
|
template <typename T, void (*function)(T*)> |
677 |
|
|
struct FunctionDeleter { |
678 |
|
199212 |
void operator()(T* pointer) const { function(pointer); } |
679 |
|
|
typedef std::unique_ptr<T, FunctionDeleter> Pointer; |
680 |
|
|
}; |
681 |
|
|
|
682 |
|
|
template <typename T, void (*function)(T*)> |
683 |
|
|
using DeleteFnPtr = typename FunctionDeleter<T, function>::Pointer; |
684 |
|
|
|
685 |
|
|
std::vector<std::string> SplitString(const std::string& in, |
686 |
|
|
char delim, |
687 |
|
|
bool skipEmpty = true); |
688 |
|
|
|
689 |
|
|
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
690 |
|
|
std::string_view str, |
691 |
|
|
v8::Isolate* isolate = nullptr); |
692 |
|
|
template <typename T, typename test_for_number = |
693 |
|
|
typename std::enable_if<std::numeric_limits<T>::is_specialized, bool>::type> |
694 |
|
|
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
695 |
|
|
const T& number, |
696 |
|
|
v8::Isolate* isolate = nullptr); |
697 |
|
|
template <typename T> |
698 |
|
|
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
699 |
|
|
const std::vector<T>& vec, |
700 |
|
|
v8::Isolate* isolate = nullptr); |
701 |
|
|
template <typename T> |
702 |
|
|
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
703 |
|
|
const std::set<T>& set, |
704 |
|
|
v8::Isolate* isolate = nullptr); |
705 |
|
|
template <typename T, typename U> |
706 |
|
|
inline v8::MaybeLocal<v8::Value> ToV8Value(v8::Local<v8::Context> context, |
707 |
|
|
const std::unordered_map<T, U>& map, |
708 |
|
|
v8::Isolate* isolate = nullptr); |
709 |
|
|
|
710 |
|
|
// These macros expects a `Isolate* isolate` and a `Local<Context> context` |
711 |
|
|
// to be in the scope. |
712 |
|
|
#define READONLY_PROPERTY(obj, name, value) \ |
713 |
|
|
do { \ |
714 |
|
|
obj->DefineOwnProperty( \ |
715 |
|
|
context, FIXED_ONE_BYTE_STRING(isolate, name), value, v8::ReadOnly) \ |
716 |
|
|
.Check(); \ |
717 |
|
|
} while (0) |
718 |
|
|
|
719 |
|
|
#define READONLY_DONT_ENUM_PROPERTY(obj, name, var) \ |
720 |
|
|
do { \ |
721 |
|
|
obj->DefineOwnProperty( \ |
722 |
|
|
context, \ |
723 |
|
|
OneByteString(isolate, name), \ |
724 |
|
|
var, \ |
725 |
|
|
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontEnum)) \ |
726 |
|
|
.Check(); \ |
727 |
|
|
} while (0) |
728 |
|
|
|
729 |
|
|
#define READONLY_FALSE_PROPERTY(obj, name) \ |
730 |
|
|
READONLY_PROPERTY(obj, name, v8::False(isolate)) |
731 |
|
|
|
732 |
|
|
#define READONLY_TRUE_PROPERTY(obj, name) \ |
733 |
|
|
READONLY_PROPERTY(obj, name, v8::True(isolate)) |
734 |
|
|
|
735 |
|
|
#define READONLY_STRING_PROPERTY(obj, name, str) \ |
736 |
|
|
READONLY_PROPERTY(obj, name, ToV8Value(context, str).ToLocalChecked()) |
737 |
|
|
|
738 |
|
|
// Variation on NODE_DEFINE_CONSTANT that sets a String value. |
739 |
|
|
#define NODE_DEFINE_STRING_CONSTANT(target, name, constant) \ |
740 |
|
|
do { \ |
741 |
|
|
v8::Isolate* isolate = target->GetIsolate(); \ |
742 |
|
|
v8::Local<v8::String> constant_name = \ |
743 |
|
|
v8::String::NewFromUtf8(isolate, name).ToLocalChecked(); \ |
744 |
|
|
v8::Local<v8::String> constant_value = \ |
745 |
|
|
v8::String::NewFromUtf8(isolate, constant).ToLocalChecked(); \ |
746 |
|
|
v8::PropertyAttribute constant_attributes = \ |
747 |
|
|
static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete); \ |
748 |
|
|
target \ |
749 |
|
|
->DefineOwnProperty(isolate->GetCurrentContext(), \ |
750 |
|
|
constant_name, \ |
751 |
|
|
constant_value, \ |
752 |
|
|
constant_attributes) \ |
753 |
|
|
.Check(); \ |
754 |
|
|
} while (0) |
755 |
|
|
|
756 |
|
|
enum class Endianness { LITTLE, BIG }; |
757 |
|
|
|
758 |
|
6726 |
inline Endianness GetEndianness() { |
759 |
|
|
// Constant-folded by the compiler. |
760 |
|
|
const union { |
761 |
|
|
uint8_t u8[2]; |
762 |
|
|
uint16_t u16; |
763 |
|
6726 |
} u = {{1, 0}}; |
764 |
✓✗ |
6726 |
return u.u16 == 1 ? Endianness::LITTLE : Endianness::BIG; |
765 |
|
|
} |
766 |
|
|
|
767 |
|
1 |
inline bool IsLittleEndian() { |
768 |
|
1 |
return GetEndianness() == Endianness::LITTLE; |
769 |
|
|
} |
770 |
|
|
|
771 |
|
6725 |
inline bool IsBigEndian() { |
772 |
|
6725 |
return GetEndianness() == Endianness::BIG; |
773 |
|
|
} |
774 |
|
|
|
775 |
|
|
// Round up a to the next highest multiple of b. |
776 |
|
|
template <typename T> |
777 |
|
184861 |
constexpr T RoundUp(T a, T b) { |
778 |
✓✓ |
184861 |
return a % b != 0 ? a + b - (a % b) : a; |
779 |
|
|
} |
780 |
|
|
|
781 |
|
|
// Align ptr to an `alignment`-bytes boundary. |
782 |
|
|
template <typename T, typename U> |
783 |
|
24087 |
constexpr T* AlignUp(T* ptr, U alignment) { |
784 |
|
|
return reinterpret_cast<T*>( |
785 |
|
24087 |
RoundUp(reinterpret_cast<uintptr_t>(ptr), alignment)); |
786 |
|
|
} |
787 |
|
|
|
788 |
|
|
class SlicedArguments : public MaybeStackBuffer<v8::Local<v8::Value>> { |
789 |
|
|
public: |
790 |
|
|
inline explicit SlicedArguments( |
791 |
|
|
const v8::FunctionCallbackInfo<v8::Value>& args, size_t start = 0); |
792 |
|
|
}; |
793 |
|
|
|
794 |
|
|
// Convert a v8::PersistentBase, e.g. v8::Global, to a Local, with an extra |
795 |
|
|
// optimization for strong persistent handles. |
796 |
|
|
class PersistentToLocal { |
797 |
|
|
public: |
798 |
|
|
// If persistent.IsWeak() == false, then do not call persistent.Reset() |
799 |
|
|
// while the returned Local<T> is still in scope, it will destroy the |
800 |
|
|
// reference to the object. |
801 |
|
|
template <class TypeName> |
802 |
|
6881333 |
static inline v8::Local<TypeName> Default( |
803 |
|
|
v8::Isolate* isolate, |
804 |
|
|
const v8::PersistentBase<TypeName>& persistent) { |
805 |
✓✓ |
6881333 |
if (persistent.IsWeak()) { |
806 |
|
4508294 |
return PersistentToLocal::Weak(isolate, persistent); |
807 |
|
|
} else { |
808 |
|
2373039 |
return PersistentToLocal::Strong(persistent); |
809 |
|
|
} |
810 |
|
|
} |
811 |
|
|
|
812 |
|
|
// Unchecked conversion from a non-weak Persistent<T> to Local<T>, |
813 |
|
|
// use with care! |
814 |
|
|
// |
815 |
|
|
// Do not call persistent.Reset() while the returned Local<T> is still in |
816 |
|
|
// scope, it will destroy the reference to the object. |
817 |
|
|
template <class TypeName> |
818 |
|
36939126 |
static inline v8::Local<TypeName> Strong( |
819 |
|
|
const v8::PersistentBase<TypeName>& persistent) { |
820 |
|
|
DCHECK(!persistent.IsWeak()); |
821 |
|
|
return *reinterpret_cast<v8::Local<TypeName>*>( |
822 |
|
36939126 |
const_cast<v8::PersistentBase<TypeName>*>(&persistent)); |
823 |
|
|
} |
824 |
|
|
|
825 |
|
|
template <class TypeName> |
826 |
✓✓ |
2378899 |
static inline v8::Local<TypeName> Weak( |
827 |
|
|
v8::Isolate* isolate, |
828 |
|
|
const v8::PersistentBase<TypeName>& persistent) { |
829 |
|
2378899 |
return v8::Local<TypeName>::New(isolate, persistent); |
830 |
|
|
} |
831 |
|
|
}; |
832 |
|
|
|
833 |
|
|
// Can be used as a key for std::unordered_map when lookup performance is more |
834 |
|
|
// important than size and the keys are statically used to avoid redundant hash |
835 |
|
|
// computations. |
836 |
|
|
class FastStringKey { |
837 |
|
|
public: |
838 |
|
|
constexpr explicit FastStringKey(const char* name); |
839 |
|
|
|
840 |
|
|
struct Hash { |
841 |
|
|
constexpr size_t operator()(const FastStringKey& key) const; |
842 |
|
|
}; |
843 |
|
|
constexpr bool operator==(const FastStringKey& other) const; |
844 |
|
|
|
845 |
|
|
constexpr const char* c_str() const; |
846 |
|
|
|
847 |
|
|
private: |
848 |
|
|
static constexpr size_t HashImpl(const char* str); |
849 |
|
|
|
850 |
|
|
const char* name_; |
851 |
|
|
size_t cached_hash_; |
852 |
|
|
}; |
853 |
|
|
|
854 |
|
|
// Like std::static_pointer_cast but for unique_ptr with the default deleter. |
855 |
|
|
template <typename T, typename U> |
856 |
|
10765 |
std::unique_ptr<T> static_unique_pointer_cast(std::unique_ptr<U>&& ptr) { |
857 |
|
10765 |
return std::unique_ptr<T>(static_cast<T*>(ptr.release())); |
858 |
|
|
} |
859 |
|
|
|
860 |
|
|
#define MAYBE_FIELD_PTR(ptr, field) ptr == nullptr ? nullptr : &(ptr->field) |
861 |
|
|
|
862 |
|
|
// Returns a non-zero code if it fails to open or read the file, |
863 |
|
|
// aborts if it fails to close the file. |
864 |
|
|
int ReadFileSync(std::string* result, const char* path); |
865 |
|
|
|
866 |
|
|
v8::Local<v8::FunctionTemplate> NewFunctionTemplate( |
867 |
|
|
v8::Isolate* isolate, |
868 |
|
|
v8::FunctionCallback callback, |
869 |
|
|
v8::Local<v8::Signature> signature = v8::Local<v8::Signature>(), |
870 |
|
|
v8::ConstructorBehavior behavior = v8::ConstructorBehavior::kAllow, |
871 |
|
|
v8::SideEffectType side_effect = v8::SideEffectType::kHasSideEffect, |
872 |
|
|
const v8::CFunction* c_function = nullptr); |
873 |
|
|
|
874 |
|
|
// Convenience methods for NewFunctionTemplate(). |
875 |
|
|
void SetMethod(v8::Local<v8::Context> context, |
876 |
|
|
v8::Local<v8::Object> that, |
877 |
|
|
const char* name, |
878 |
|
|
v8::FunctionCallback callback); |
879 |
|
|
|
880 |
|
|
void SetFastMethod(v8::Local<v8::Context> context, |
881 |
|
|
v8::Local<v8::Object> that, |
882 |
|
|
const char* name, |
883 |
|
|
v8::FunctionCallback slow_callback, |
884 |
|
|
const v8::CFunction* c_function); |
885 |
|
|
|
886 |
|
|
void SetProtoMethod(v8::Isolate* isolate, |
887 |
|
|
v8::Local<v8::FunctionTemplate> that, |
888 |
|
|
const char* name, |
889 |
|
|
v8::FunctionCallback callback); |
890 |
|
|
|
891 |
|
|
void SetInstanceMethod(v8::Isolate* isolate, |
892 |
|
|
v8::Local<v8::FunctionTemplate> that, |
893 |
|
|
const char* name, |
894 |
|
|
v8::FunctionCallback callback); |
895 |
|
|
|
896 |
|
|
// Safe variants denote the function has no side effects. |
897 |
|
|
void SetMethodNoSideEffect(v8::Local<v8::Context> context, |
898 |
|
|
v8::Local<v8::Object> that, |
899 |
|
|
const char* name, |
900 |
|
|
v8::FunctionCallback callback); |
901 |
|
|
void SetProtoMethodNoSideEffect(v8::Isolate* isolate, |
902 |
|
|
v8::Local<v8::FunctionTemplate> that, |
903 |
|
|
const char* name, |
904 |
|
|
v8::FunctionCallback callback); |
905 |
|
|
|
906 |
|
|
enum class SetConstructorFunctionFlag { |
907 |
|
|
NONE, |
908 |
|
|
SET_CLASS_NAME, |
909 |
|
|
}; |
910 |
|
|
|
911 |
|
|
void SetConstructorFunction(v8::Local<v8::Context> context, |
912 |
|
|
v8::Local<v8::Object> that, |
913 |
|
|
const char* name, |
914 |
|
|
v8::Local<v8::FunctionTemplate> tmpl, |
915 |
|
|
SetConstructorFunctionFlag flag = |
916 |
|
|
SetConstructorFunctionFlag::SET_CLASS_NAME); |
917 |
|
|
|
918 |
|
|
void SetConstructorFunction(v8::Local<v8::Context> context, |
919 |
|
|
v8::Local<v8::Object> that, |
920 |
|
|
v8::Local<v8::String> name, |
921 |
|
|
v8::Local<v8::FunctionTemplate> tmpl, |
922 |
|
|
SetConstructorFunctionFlag flag = |
923 |
|
|
SetConstructorFunctionFlag::SET_CLASS_NAME); |
924 |
|
|
|
925 |
|
|
} // namespace node |
926 |
|
|
|
927 |
|
|
#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS |
928 |
|
|
|
929 |
|
|
#endif // SRC_UTIL_H_ |