js/public/Utility.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

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 */

mercurial