|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
|
2 * vim: set ts=8 sts=4 et sw=4 tw=99: |
|
3 * This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #ifndef js_Utility_h |
|
8 #define js_Utility_h |
|
9 |
|
10 #include "mozilla/Assertions.h" |
|
11 #include "mozilla/Attributes.h" |
|
12 #include "mozilla/Compiler.h" |
|
13 #include "mozilla/Move.h" |
|
14 #include "mozilla/NullPtr.h" |
|
15 #include "mozilla/Scoped.h" |
|
16 #include "mozilla/TemplateLib.h" |
|
17 |
|
18 #include <stdlib.h> |
|
19 #include <string.h> |
|
20 |
|
21 #ifdef JS_OOM_DO_BACKTRACES |
|
22 #include <execinfo.h> |
|
23 #include <stdio.h> |
|
24 #endif |
|
25 |
|
26 #include "jstypes.h" |
|
27 |
|
28 /* The public JS engine namespace. */ |
|
29 namespace JS {} |
|
30 |
|
31 /* The mozilla-shared reusable template/utility namespace. */ |
|
32 namespace mozilla {} |
|
33 |
|
34 /* The private JS engine namespace. */ |
|
35 namespace js {} |
|
36 |
|
37 /* |
|
38 * Patterns used by SpiderMonkey to overwrite unused memory. If you are |
|
39 * accessing an object with one of these pattern, you probably have a dangling |
|
40 * pointer. |
|
41 */ |
|
42 #define JS_FRESH_NURSERY_PATTERN 0x2F |
|
43 #define JS_SWEPT_NURSERY_PATTERN 0x2B |
|
44 #define JS_ALLOCATED_NURSERY_PATTERN 0x2D |
|
45 #define JS_FRESH_TENURED_PATTERN 0x4F |
|
46 #define JS_SWEPT_TENURED_PATTERN 0x4B |
|
47 #define JS_ALLOCATED_TENURED_PATTERN 0x4D |
|
48 #define JS_SWEPT_CODE_PATTERN 0x3b |
|
49 #define JS_SWEPT_FRAME_PATTERN 0x5b |
|
50 |
|
51 #define JS_ASSERT(expr) MOZ_ASSERT(expr) |
|
52 #define JS_ASSERT_IF(cond, expr) MOZ_ASSERT_IF(cond, expr) |
|
53 |
|
54 #define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT") |
|
55 #define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF") |
|
56 |
|
57 extern MOZ_NORETURN JS_PUBLIC_API(void) |
|
58 JS_Assert(const char *s, const char *file, int ln); |
|
59 |
|
60 /* |
|
61 * Abort the process in a non-graceful manner. This will cause a core file, |
|
62 * call to the debugger or other moral equivalent as well as causing the |
|
63 * entire process to stop. |
|
64 */ |
|
65 extern JS_PUBLIC_API(void) JS_Abort(void); |
|
66 |
|
67 /* |
|
68 * Custom allocator support for SpiderMonkey |
|
69 */ |
|
70 #if defined JS_USE_CUSTOM_ALLOCATOR |
|
71 # include "jscustomallocator.h" |
|
72 #else |
|
73 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) |
|
74 /* |
|
75 * In order to test OOM conditions, when the testing function |
|
76 * oomAfterAllocations COUNT is passed, we fail continuously after the NUM'th |
|
77 * allocation from now. |
|
78 */ |
|
79 extern JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations; /* set in builtin/TestingFunctions.cpp */ |
|
80 extern JS_PUBLIC_DATA(uint32_t) OOM_counter; /* data race, who cares. */ |
|
81 |
|
82 #ifdef JS_OOM_BREAKPOINT |
|
83 static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } |
|
84 #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() |
|
85 #else |
|
86 #define JS_OOM_CALL_BP_FUNC() do {} while(0) |
|
87 #endif |
|
88 |
|
89 # define JS_OOM_POSSIBLY_FAIL() \ |
|
90 do \ |
|
91 { \ |
|
92 if (++OOM_counter > OOM_maxAllocations) { \ |
|
93 JS_OOM_CALL_BP_FUNC();\ |
|
94 return nullptr; \ |
|
95 } \ |
|
96 } while (0) |
|
97 |
|
98 # else |
|
99 # define JS_OOM_POSSIBLY_FAIL() do {} while(0) |
|
100 # endif /* DEBUG || JS_OOM_BREAKPOINT */ |
|
101 |
|
102 static inline void* js_malloc(size_t bytes) |
|
103 { |
|
104 JS_OOM_POSSIBLY_FAIL(); |
|
105 return malloc(bytes); |
|
106 } |
|
107 |
|
108 static inline void* js_calloc(size_t bytes) |
|
109 { |
|
110 JS_OOM_POSSIBLY_FAIL(); |
|
111 return calloc(bytes, 1); |
|
112 } |
|
113 |
|
114 static inline void* js_calloc(size_t nmemb, size_t size) |
|
115 { |
|
116 JS_OOM_POSSIBLY_FAIL(); |
|
117 return calloc(nmemb, size); |
|
118 } |
|
119 |
|
120 static inline void* js_realloc(void* p, size_t bytes) |
|
121 { |
|
122 JS_OOM_POSSIBLY_FAIL(); |
|
123 return realloc(p, bytes); |
|
124 } |
|
125 |
|
126 static inline void js_free(void* p) |
|
127 { |
|
128 free(p); |
|
129 } |
|
130 #endif/* JS_USE_CUSTOM_ALLOCATOR */ |
|
131 |
|
132 #include <new> |
|
133 |
|
134 /* |
|
135 * Low-level memory management in SpiderMonkey: |
|
136 * |
|
137 * ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these |
|
138 * to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's |
|
139 * these symbols. |
|
140 * |
|
141 * ** Do not use the builtin C++ operator new and delete: these throw on |
|
142 * error and we cannot override them not to. |
|
143 * |
|
144 * Allocation: |
|
145 * |
|
146 * - If the lifetime of the allocation is tied to the lifetime of a GC-thing |
|
147 * (that is, finalizing the GC-thing will free the allocation), call one of |
|
148 * the following functions: |
|
149 * |
|
150 * JSContext::{malloc_,realloc_,calloc_,new_} |
|
151 * JSRuntime::{malloc_,realloc_,calloc_,new_} |
|
152 * |
|
153 * These functions accumulate the number of bytes allocated which is used as |
|
154 * part of the GC-triggering heuristic. |
|
155 * |
|
156 * The difference between the JSContext and JSRuntime versions is that the |
|
157 * cx version reports an out-of-memory error on OOM. (This follows from the |
|
158 * general SpiderMonkey idiom that a JSContext-taking function reports its |
|
159 * own errors.) |
|
160 * |
|
161 * - Otherwise, use js_malloc/js_realloc/js_calloc/js_free/js_new |
|
162 * |
|
163 * Deallocation: |
|
164 * |
|
165 * - Ordinarily, use js_free/js_delete. |
|
166 * |
|
167 * - For deallocations during GC finalization, use one of the following |
|
168 * operations on the FreeOp provided to the finalizer: |
|
169 * |
|
170 * FreeOp::{free_,delete_} |
|
171 * |
|
172 * The advantage of these operations is that the memory is batched and freed |
|
173 * on another thread. |
|
174 */ |
|
175 |
|
176 #define JS_NEW_BODY(allocator, t, parms) \ |
|
177 void *memory = allocator(sizeof(t)); \ |
|
178 return memory ? new(memory) t parms : nullptr; |
|
179 |
|
180 /* |
|
181 * Given a class which should provide 'new' methods, add |
|
182 * JS_DECLARE_NEW_METHODS (see JSContext for a usage example). This |
|
183 * adds news with up to 12 parameters. Add more versions of new below if |
|
184 * you need more than 12 parameters. |
|
185 * |
|
186 * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS, |
|
187 * or the build will break. |
|
188 */ |
|
189 #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS)\ |
|
190 template <class T>\ |
|
191 QUALIFIERS T *NEWNAME() MOZ_HEAP_ALLOCATOR {\ |
|
192 JS_NEW_BODY(ALLOCATOR, T, ())\ |
|
193 }\ |
|
194 \ |
|
195 template <class T, class P1>\ |
|
196 QUALIFIERS T *NEWNAME(P1 &&p1) MOZ_HEAP_ALLOCATOR {\ |
|
197 JS_NEW_BODY(ALLOCATOR, T,\ |
|
198 (mozilla::Forward<P1>(p1)))\ |
|
199 }\ |
|
200 \ |
|
201 template <class T, class P1, class P2>\ |
|
202 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2) MOZ_HEAP_ALLOCATOR {\ |
|
203 JS_NEW_BODY(ALLOCATOR, T,\ |
|
204 (mozilla::Forward<P1>(p1),\ |
|
205 mozilla::Forward<P2>(p2)))\ |
|
206 }\ |
|
207 \ |
|
208 template <class T, class P1, class P2, class P3>\ |
|
209 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3) MOZ_HEAP_ALLOCATOR {\ |
|
210 JS_NEW_BODY(ALLOCATOR, T,\ |
|
211 (mozilla::Forward<P1>(p1),\ |
|
212 mozilla::Forward<P2>(p2),\ |
|
213 mozilla::Forward<P3>(p3)))\ |
|
214 }\ |
|
215 \ |
|
216 template <class T, class P1, class P2, class P3, class P4>\ |
|
217 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4) MOZ_HEAP_ALLOCATOR {\ |
|
218 JS_NEW_BODY(ALLOCATOR, T,\ |
|
219 (mozilla::Forward<P1>(p1),\ |
|
220 mozilla::Forward<P2>(p2),\ |
|
221 mozilla::Forward<P3>(p3),\ |
|
222 mozilla::Forward<P4>(p4)))\ |
|
223 }\ |
|
224 \ |
|
225 template <class T, class P1, class P2, class P3, class P4, class P5>\ |
|
226 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5) MOZ_HEAP_ALLOCATOR {\ |
|
227 JS_NEW_BODY(ALLOCATOR, T,\ |
|
228 (mozilla::Forward<P1>(p1),\ |
|
229 mozilla::Forward<P2>(p2),\ |
|
230 mozilla::Forward<P3>(p3),\ |
|
231 mozilla::Forward<P4>(p4),\ |
|
232 mozilla::Forward<P5>(p5)))\ |
|
233 }\ |
|
234 \ |
|
235 template <class T, class P1, class P2, class P3, class P4, class P5, class P6>\ |
|
236 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6) MOZ_HEAP_ALLOCATOR {\ |
|
237 JS_NEW_BODY(ALLOCATOR, T,\ |
|
238 (mozilla::Forward<P1>(p1),\ |
|
239 mozilla::Forward<P2>(p2),\ |
|
240 mozilla::Forward<P3>(p3),\ |
|
241 mozilla::Forward<P4>(p4),\ |
|
242 mozilla::Forward<P5>(p5),\ |
|
243 mozilla::Forward<P6>(p6)))\ |
|
244 }\ |
|
245 \ |
|
246 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7>\ |
|
247 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7) MOZ_HEAP_ALLOCATOR {\ |
|
248 JS_NEW_BODY(ALLOCATOR, T,\ |
|
249 (mozilla::Forward<P1>(p1),\ |
|
250 mozilla::Forward<P2>(p2),\ |
|
251 mozilla::Forward<P3>(p3),\ |
|
252 mozilla::Forward<P4>(p4),\ |
|
253 mozilla::Forward<P5>(p5),\ |
|
254 mozilla::Forward<P6>(p6),\ |
|
255 mozilla::Forward<P7>(p7)))\ |
|
256 }\ |
|
257 \ |
|
258 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>\ |
|
259 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8) MOZ_HEAP_ALLOCATOR {\ |
|
260 JS_NEW_BODY(ALLOCATOR, T,\ |
|
261 (mozilla::Forward<P1>(p1),\ |
|
262 mozilla::Forward<P2>(p2),\ |
|
263 mozilla::Forward<P3>(p3),\ |
|
264 mozilla::Forward<P4>(p4),\ |
|
265 mozilla::Forward<P5>(p5),\ |
|
266 mozilla::Forward<P6>(p6),\ |
|
267 mozilla::Forward<P7>(p7),\ |
|
268 mozilla::Forward<P8>(p8)))\ |
|
269 }\ |
|
270 \ |
|
271 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>\ |
|
272 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9) MOZ_HEAP_ALLOCATOR {\ |
|
273 JS_NEW_BODY(ALLOCATOR, T,\ |
|
274 (mozilla::Forward<P1>(p1),\ |
|
275 mozilla::Forward<P2>(p2),\ |
|
276 mozilla::Forward<P3>(p3),\ |
|
277 mozilla::Forward<P4>(p4),\ |
|
278 mozilla::Forward<P5>(p5),\ |
|
279 mozilla::Forward<P6>(p6),\ |
|
280 mozilla::Forward<P7>(p7),\ |
|
281 mozilla::Forward<P8>(p8),\ |
|
282 mozilla::Forward<P9>(p9)))\ |
|
283 }\ |
|
284 \ |
|
285 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10>\ |
|
286 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10) MOZ_HEAP_ALLOCATOR {\ |
|
287 JS_NEW_BODY(ALLOCATOR, T,\ |
|
288 (mozilla::Forward<P1>(p1),\ |
|
289 mozilla::Forward<P2>(p2),\ |
|
290 mozilla::Forward<P3>(p3),\ |
|
291 mozilla::Forward<P4>(p4),\ |
|
292 mozilla::Forward<P5>(p5),\ |
|
293 mozilla::Forward<P6>(p6),\ |
|
294 mozilla::Forward<P7>(p7),\ |
|
295 mozilla::Forward<P8>(p8),\ |
|
296 mozilla::Forward<P9>(p9),\ |
|
297 mozilla::Forward<P10>(p10)))\ |
|
298 }\ |
|
299 \ |
|
300 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11>\ |
|
301 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11) MOZ_HEAP_ALLOCATOR {\ |
|
302 JS_NEW_BODY(ALLOCATOR, T,\ |
|
303 (mozilla::Forward<P1>(p1),\ |
|
304 mozilla::Forward<P2>(p2),\ |
|
305 mozilla::Forward<P3>(p3),\ |
|
306 mozilla::Forward<P4>(p4),\ |
|
307 mozilla::Forward<P5>(p5),\ |
|
308 mozilla::Forward<P6>(p6),\ |
|
309 mozilla::Forward<P7>(p7),\ |
|
310 mozilla::Forward<P8>(p8),\ |
|
311 mozilla::Forward<P9>(p9),\ |
|
312 mozilla::Forward<P10>(p10),\ |
|
313 mozilla::Forward<P11>(p11)))\ |
|
314 }\ |
|
315 \ |
|
316 template <class T, class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9, class P10, class P11, class P12>\ |
|
317 QUALIFIERS T *NEWNAME(P1 &&p1, P2 &&p2, P3 &&p3, P4 &&p4, P5 &&p5, P6 &&p6, P7 &&p7, P8 &&p8, P9 &&p9, P10 &&p10, P11 &&p11, P12 &&p12) MOZ_HEAP_ALLOCATOR {\ |
|
318 JS_NEW_BODY(ALLOCATOR, T,\ |
|
319 (mozilla::Forward<P1>(p1),\ |
|
320 mozilla::Forward<P2>(p2),\ |
|
321 mozilla::Forward<P3>(p3),\ |
|
322 mozilla::Forward<P4>(p4),\ |
|
323 mozilla::Forward<P5>(p5),\ |
|
324 mozilla::Forward<P6>(p6),\ |
|
325 mozilla::Forward<P7>(p7),\ |
|
326 mozilla::Forward<P8>(p8),\ |
|
327 mozilla::Forward<P9>(p9),\ |
|
328 mozilla::Forward<P10>(p10),\ |
|
329 mozilla::Forward<P11>(p11),\ |
|
330 mozilla::Forward<P12>(p12)))\ |
|
331 }\ |
|
332 |
|
333 JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE) |
|
334 |
|
335 template <class T> |
|
336 static MOZ_ALWAYS_INLINE void |
|
337 js_delete(T *p) |
|
338 { |
|
339 if (p) { |
|
340 p->~T(); |
|
341 js_free(p); |
|
342 } |
|
343 } |
|
344 |
|
345 template<class T> |
|
346 static MOZ_ALWAYS_INLINE void |
|
347 js_delete_poison(T *p) |
|
348 { |
|
349 if (p) { |
|
350 p->~T(); |
|
351 memset(p, 0x3B, sizeof(T)); |
|
352 js_free(p); |
|
353 } |
|
354 } |
|
355 |
|
356 template <class T> |
|
357 static MOZ_ALWAYS_INLINE T * |
|
358 js_pod_malloc() |
|
359 { |
|
360 return (T *)js_malloc(sizeof(T)); |
|
361 } |
|
362 |
|
363 template <class T> |
|
364 static MOZ_ALWAYS_INLINE T * |
|
365 js_pod_calloc() |
|
366 { |
|
367 return (T *)js_calloc(sizeof(T)); |
|
368 } |
|
369 |
|
370 template <class T> |
|
371 static MOZ_ALWAYS_INLINE T * |
|
372 js_pod_malloc(size_t numElems) |
|
373 { |
|
374 if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) |
|
375 return nullptr; |
|
376 return (T *)js_malloc(numElems * sizeof(T)); |
|
377 } |
|
378 |
|
379 template <class T> |
|
380 static MOZ_ALWAYS_INLINE T * |
|
381 js_pod_calloc(size_t numElems) |
|
382 { |
|
383 if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) |
|
384 return nullptr; |
|
385 return (T *)js_calloc(numElems * sizeof(T)); |
|
386 } |
|
387 |
|
388 namespace js { |
|
389 |
|
390 template<typename T> |
|
391 struct ScopedFreePtrTraits |
|
392 { |
|
393 typedef T* type; |
|
394 static T* empty() { return nullptr; } |
|
395 static void release(T* ptr) { js_free(ptr); } |
|
396 }; |
|
397 SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits) |
|
398 |
|
399 template <typename T> |
|
400 struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T> |
|
401 { |
|
402 static void release(T *ptr) { js_delete(ptr); } |
|
403 }; |
|
404 SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits) |
|
405 |
|
406 template <typename T> |
|
407 struct ScopedReleasePtrTraits : public ScopedFreePtrTraits<T> |
|
408 { |
|
409 static void release(T *ptr) { if (ptr) ptr->release(); } |
|
410 }; |
|
411 SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits) |
|
412 |
|
413 } /* namespace js */ |
|
414 |
|
415 namespace js { |
|
416 |
|
417 /* Integral types for all hash functions. */ |
|
418 typedef uint32_t HashNumber; |
|
419 const unsigned HashNumberSizeBits = 32; |
|
420 |
|
421 namespace detail { |
|
422 |
|
423 /* |
|
424 * Given a raw hash code, h, return a number that can be used to select a hash |
|
425 * bucket. |
|
426 * |
|
427 * This function aims to produce as uniform an output distribution as possible, |
|
428 * especially in the most significant (leftmost) bits, even though the input |
|
429 * distribution may be highly nonrandom, given the constraints that this must |
|
430 * be deterministic and quick to compute. |
|
431 * |
|
432 * Since the leftmost bits of the result are best, the hash bucket index is |
|
433 * computed by doing ScrambleHashCode(h) / (2^32/N) or the equivalent |
|
434 * right-shift, not ScrambleHashCode(h) % N or the equivalent bit-mask. |
|
435 * |
|
436 * FIXME: OrderedHashTable uses a bit-mask; see bug 775896. |
|
437 */ |
|
438 inline HashNumber |
|
439 ScrambleHashCode(HashNumber h) |
|
440 { |
|
441 /* |
|
442 * Simply returning h would not cause any hash tables to produce wrong |
|
443 * answers. But it can produce pathologically bad performance: The caller |
|
444 * right-shifts the result, keeping only the highest bits. The high bits of |
|
445 * hash codes are very often completely entropy-free. (So are the lowest |
|
446 * bits.) |
|
447 * |
|
448 * So we use Fibonacci hashing, as described in Knuth, The Art of Computer |
|
449 * Programming, 6.4. This mixes all the bits of the input hash code h. |
|
450 * |
|
451 * The value of goldenRatio is taken from the hex |
|
452 * expansion of the golden ratio, which starts 1.9E3779B9.... |
|
453 * This value is especially good if values with consecutive hash codes |
|
454 * are stored in a hash table; see Knuth for details. |
|
455 */ |
|
456 static const HashNumber goldenRatio = 0x9E3779B9U; |
|
457 return h * goldenRatio; |
|
458 } |
|
459 |
|
460 } /* namespace detail */ |
|
461 |
|
462 } /* namespace js */ |
|
463 |
|
464 namespace JS { |
|
465 |
|
466 /* |
|
467 * Methods for poisoning GC heap pointer words and checking for poisoned words. |
|
468 * These are in this file for use in Value methods and so forth. |
|
469 * |
|
470 * If the moving GC hazard analysis is in use and detects a non-rooted stack |
|
471 * pointer to a GC thing, one byte of that pointer is poisoned to refer to an |
|
472 * invalid location. For both 32 bit and 64 bit systems, the fourth byte of the |
|
473 * pointer is overwritten, to reduce the likelihood of accidentally changing |
|
474 * a live integer value. |
|
475 */ |
|
476 |
|
477 inline void PoisonPtr(void *v) |
|
478 { |
|
479 #if defined(JSGC_ROOT_ANALYSIS) && defined(JS_DEBUG) |
|
480 uint8_t *ptr = (uint8_t *) v + 3; |
|
481 *ptr = JS_FREE_PATTERN; |
|
482 #endif |
|
483 } |
|
484 |
|
485 template <typename T> |
|
486 inline bool IsPoisonedPtr(T *v) |
|
487 { |
|
488 #if defined(JSGC_ROOT_ANALYSIS) && defined(JS_DEBUG) |
|
489 uint32_t mask = uintptr_t(v) & 0xff000000; |
|
490 return mask == uint32_t(JS_FREE_PATTERN << 24); |
|
491 #else |
|
492 return false; |
|
493 #endif |
|
494 } |
|
495 |
|
496 } |
|
497 |
|
498 /* sixgill annotation defines */ |
|
499 #ifndef HAVE_STATIC_ANNOTATIONS |
|
500 # define HAVE_STATIC_ANNOTATIONS |
|
501 # ifdef XGILL_PLUGIN |
|
502 # define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) |
|
503 # define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND))) |
|
504 # define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) |
|
505 # define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND))) |
|
506 # define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) |
|
507 # define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND))) |
|
508 # define STATIC_PASTE2(X,Y) X ## Y |
|
509 # define STATIC_PASTE1(X,Y) STATIC_PASTE2(X,Y) |
|
510 # define STATIC_ASSERT(COND) \ |
|
511 JS_BEGIN_MACRO \ |
|
512 __attribute__((assert_static(#COND), unused)) \ |
|
513 int STATIC_PASTE1(assert_static_, __COUNTER__); \ |
|
514 JS_END_MACRO |
|
515 # define STATIC_ASSUME(COND) \ |
|
516 JS_BEGIN_MACRO \ |
|
517 __attribute__((assume_static(#COND), unused)) \ |
|
518 int STATIC_PASTE1(assume_static_, __COUNTER__); \ |
|
519 JS_END_MACRO |
|
520 # define STATIC_ASSERT_RUNTIME(COND) \ |
|
521 JS_BEGIN_MACRO \ |
|
522 __attribute__((assert_static_runtime(#COND), unused)) \ |
|
523 int STATIC_PASTE1(assert_static_runtime_, __COUNTER__); \ |
|
524 JS_END_MACRO |
|
525 # else /* XGILL_PLUGIN */ |
|
526 # define STATIC_PRECONDITION(COND) /* nothing */ |
|
527 # define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ |
|
528 # define STATIC_POSTCONDITION(COND) /* nothing */ |
|
529 # define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ |
|
530 # define STATIC_INVARIANT(COND) /* nothing */ |
|
531 # define STATIC_INVARIANT_ASSUME(COND) /* nothing */ |
|
532 # define STATIC_ASSERT(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO |
|
533 # define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO |
|
534 # define STATIC_ASSERT_RUNTIME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO |
|
535 # endif /* XGILL_PLUGIN */ |
|
536 # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) |
|
537 #endif /* HAVE_STATIC_ANNOTATIONS */ |
|
538 |
|
539 #endif /* js_Utility_h */ |