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