diff options
Diffstat (limited to 'js/src/jsutil.cpp')
-rw-r--r-- | js/src/jsutil.cpp | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/js/src/jsutil.cpp b/js/src/jsutil.cpp new file mode 100644 index 000000000..bb9f33df9 --- /dev/null +++ b/js/src/jsutil.cpp @@ -0,0 +1,281 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=8 sts=4 et sw=4 tw=99: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Various JS utility functions. */ + +#include "jsutil.h" + +#include "mozilla/Assertions.h" +#include "mozilla/MathAlgorithms.h" +#include "mozilla/PodOperations.h" +#include "mozilla/ThreadLocal.h" + +#include <stdio.h> + +#include "jstypes.h" + +#include "vm/HelperThreads.h" + +#ifdef WIN32 +# include "jswin.h" +#endif + +#include "js/Utility.h" + +using namespace js; + +using mozilla::CeilingLog2Size; +using mozilla::PodArrayZero; + +#if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) +/* For OOM testing functionality in Utility.h. */ +namespace js { + +mozilla::Atomic<AutoEnterOOMUnsafeRegion*> AutoEnterOOMUnsafeRegion::owner_; + +namespace oom { + +JS_PUBLIC_DATA(uint32_t) targetThread = 0; +JS_PUBLIC_DATA(MOZ_THREAD_LOCAL(uint32_t)) threadType; +JS_PUBLIC_DATA(uint64_t) maxAllocations = UINT64_MAX; +JS_PUBLIC_DATA(uint64_t) counter = 0; +JS_PUBLIC_DATA(bool) failAlways = true; + +bool +InitThreadType(void) { + return threadType.init(); +} + +void +SetThreadType(ThreadType type) { + threadType.set(type); +} + +uint32_t +GetThreadType(void) { + return threadType.get(); +} + +void +SimulateOOMAfter(uint64_t allocations, uint32_t thread, bool always) { + MOZ_ASSERT(counter + allocations > counter); + MOZ_ASSERT(thread > js::oom::THREAD_TYPE_NONE && thread < js::oom::THREAD_TYPE_MAX); + targetThread = thread; + maxAllocations = counter + allocations; + failAlways = always; +} + +void +ResetSimulatedOOM() { + if (targetThread != THREAD_TYPE_NONE && targetThread != THREAD_TYPE_MAIN) + HelperThreadState().waitForAllThreads(); + targetThread = THREAD_TYPE_NONE; + maxAllocations = UINT64_MAX; + failAlways = false; +} + + +} // namespace oom +} // namespace js +#endif // defined(DEBUG) || defined(JS_OOM_BREAKPOINT) + +JS_PUBLIC_API(void) +JS_Assert(const char* s, const char* file, int ln) +{ + MOZ_ReportAssertionFailure(s, file, ln); + MOZ_CRASH(); +} + +#ifdef __linux__ + +#include <malloc.h> +#include <stdlib.h> + +namespace js { + +// This function calls all the vanilla heap allocation functions. It is never +// called, and exists purely to help config/check_vanilla_allocations.py. See +// that script for more details. +extern MOZ_COLD void +AllTheNonBasicVanillaNewAllocations() +{ + // posix_memalign and aligned_alloc aren't available on all Linux + // configurations. + // valloc was deprecated in Android 5.0 + //char* q; + //posix_memalign((void**)&q, 16, 16); + + intptr_t p = + intptr_t(malloc(16)) + + intptr_t(calloc(1, 16)) + + intptr_t(realloc(nullptr, 16)) + + intptr_t(new char) + + intptr_t(new char) + + intptr_t(new char) + + intptr_t(new char[16]) + + intptr_t(memalign(16, 16)) + + //intptr_t(q) + + //intptr_t(aligned_alloc(16, 16)) + + //intptr_t(valloc(4096)) + + intptr_t(strdup("dummy")); + + printf("%u\n", uint32_t(p)); // make sure |p| is not optimized away + + free((int*)p); // this would crash if ever actually called + + MOZ_CRASH(); +} + +} // namespace js + +#endif // __linux__ + +#ifdef JS_BASIC_STATS + +#include <math.h> + +/* + * Histogram bins count occurrences of values <= the bin label, as follows: + * + * linear: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or more + * 2**x: 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 or more + * 10**x: 0, 1, 10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 or more + * + * We wish to count occurrences of 0 and 1 values separately, always. + */ +static uint32_t +BinToVal(unsigned logscale, unsigned bin) +{ + MOZ_ASSERT(bin <= 10); + if (bin <= 1 || logscale == 0) + return bin; + --bin; + if (logscale == 2) + return JS_BIT(bin); + MOZ_ASSERT(logscale == 10); + return uint32_t(pow(10.0, (double) bin)); +} + +static unsigned +ValToBin(unsigned logscale, uint32_t val) +{ + unsigned bin; + + if (val <= 1) + return val; + bin = (logscale == 10) + ? (unsigned) ceil(log10((double) val)) + : (logscale == 2) + ? (unsigned) CeilingLog2Size(val) + : val; + return Min(bin, 10U); +} + +void +JS_BasicStatsAccum(JSBasicStats* bs, uint32_t val) +{ + unsigned oldscale, newscale, bin; + double mean; + + ++bs->num; + if (bs->max < val) + bs->max = val; + bs->sum += val; + bs->sqsum += (double)val * val; + + oldscale = bs->logscale; + if (oldscale != 10) { + mean = bs->sum / bs->num; + if (bs->max > 16 && mean > 8) { + newscale = (bs->max > 1e6 && mean > 1000) ? 10 : 2; + if (newscale != oldscale) { + uint32_t newhist[11], newbin; + + PodArrayZero(newhist); + for (bin = 0; bin <= 10; bin++) { + newbin = ValToBin(newscale, BinToVal(oldscale, bin)); + newhist[newbin] += bs->hist[bin]; + } + js_memcpy(bs->hist, newhist, sizeof bs->hist); + bs->logscale = newscale; + } + } + } + + bin = ValToBin(bs->logscale, val); + ++bs->hist[bin]; +} + +double +JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double* sigma) +{ + double var; + + if (num == 0 || sum == 0) { + *sigma = 0; + return 0; + } + + var = num * sqsum - sum * sum; + if (var < 0 || num == 1) + var = 0; + else + var /= (double)num * (num - 1); + + /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */ + *sigma = (var != 0) ? sqrt(var) : 0; + return sum / num; +} + +void +JS_DumpBasicStats(JSBasicStats* bs, const char* title, FILE* fp) +{ + double mean, sigma; + + mean = JS_MeanAndStdDevBS(bs, &sigma); + fprintf(fp, "\nmean %s %g, std. deviation %g, max %lu\n", + title, mean, sigma, (unsigned long) bs->max); + JS_DumpHistogram(bs, fp); +} + +void +JS_DumpHistogram(JSBasicStats* bs, FILE* fp) +{ + unsigned bin; + uint32_t cnt, max; + double sum, mean; + + for (bin = 0, max = 0, sum = 0; bin <= 10; bin++) { + cnt = bs->hist[bin]; + if (max < cnt) + max = cnt; + sum += cnt; + } + mean = sum / cnt; + for (bin = 0; bin <= 10; bin++) { + unsigned val = BinToVal(bs->logscale, bin); + unsigned end = (bin == 10) ? 0 : BinToVal(bs->logscale, bin + 1); + cnt = bs->hist[bin]; + if (val + 1 == end) + fprintf(fp, " [%6u]", val); + else if (end != 0) + fprintf(fp, "[%6u, %6u]", val, end - 1); + else + fprintf(fp, "[%6u, +inf]", val); + fprintf(fp, ": %8u ", cnt); + if (cnt != 0) { + if (max > 1e6 && mean > 1e3) + cnt = uint32_t(ceil(log10((double) cnt))); + else if (max > 16 && mean > 8) + cnt = CeilingLog2Size(cnt); + for (unsigned i = 0; i < cnt; i++) + putc('*', fp); + } + putc('\n', fp); + } +} + +#endif /* JS_BASIC_STATS */ |