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 /* Various JS utility functions. */
8 
9 #include "jsutil.h"
10 
11 #include "mozilla/Assertions.h"
12 #include "mozilla/MathAlgorithms.h"
13 #include "mozilla/PodOperations.h"
14 #include "mozilla/ThreadLocal.h"
15 
16 #include <stdio.h>
17 
18 #include "jstypes.h"
19 
20 #ifdef WIN32
21 #    include "jswin.h"
22 #endif
23 
24 #include "js/Utility.h"
25 
26 using namespace js;
27 
28 using mozilla::CeilingLog2Size;
29 using mozilla::PodArrayZero;
30 
31 #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
32 /* For JS_OOM_POSSIBLY_FAIL in jsutil.h. */
33 JS_PUBLIC_DATA(uint32_t) OOM_maxAllocations = UINT32_MAX;
34 JS_PUBLIC_DATA(uint32_t) OOM_counter = 0;
35 JS_PUBLIC_DATA(bool) OOM_failAlways = true;
36 namespace js {
37 namespace oom {
38 
39 JS_PUBLIC_DATA(uint32_t) targetThread = 0;
40 JS_PUBLIC_DATA(mozilla::ThreadLocal<uint32_t>) threadType;
41 
42 bool
InitThreadType(void)43 InitThreadType(void) {
44     return threadType.initialized() || threadType.init();
45 }
46 
47 void
SetThreadType(ThreadType type)48 SetThreadType(ThreadType type) {
49     threadType.set(type);
50 }
51 
52 uint32_t
GetThreadType(void)53 GetThreadType(void) {
54     return threadType.get();
55 }
56 
57 } // namespace oom
58 } // namespace js
59 #endif // defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
60 
61 JS_PUBLIC_API(void)
JS_Assert(const char * s,const char * file,int ln)62 JS_Assert(const char* s, const char* file, int ln)
63 {
64     MOZ_ReportAssertionFailure(s, file, ln);
65     MOZ_CRASH();
66 }
67 
68 #ifdef __linux__
69 
70 #include <malloc.h>
71 #include <stdlib.h>
72 
73 namespace js {
74 
75 // This function calls all the vanilla heap allocation functions.  It is never
76 // called, and exists purely to help config/check_vanilla_allocations.py.  See
77 // that script for more details.
78 extern MOZ_COLD void
AllTheNonBasicVanillaNewAllocations()79 AllTheNonBasicVanillaNewAllocations()
80 {
81     // posix_memalign and aligned_alloc aren't available on all Linux
82     // configurations.
83     // valloc was deprecated in Android 5.0
84     //char* q;
85     //posix_memalign((void**)&q, 16, 16);
86 
87     intptr_t p =
88         intptr_t(malloc(16)) +
89         intptr_t(calloc(1, 16)) +
90         intptr_t(realloc(nullptr, 16)) +
91         intptr_t(new char) +
92         intptr_t(new char) +
93         intptr_t(new char) +
94         intptr_t(new char[16]) +
95         intptr_t(memalign(16, 16)) +
96         //intptr_t(q) +
97         //intptr_t(aligned_alloc(16, 16)) +
98         //intptr_t(valloc(4096)) +
99         intptr_t(strdup("dummy"));
100 
101     printf("%u\n", uint32_t(p));  // make sure |p| is not optimized away
102 
103     free((int*)p);      // this would crash if ever actually called
104 
105     MOZ_CRASH();
106 }
107 
108 } // namespace js
109 
110 #endif // __linux__
111 
112 #ifdef JS_BASIC_STATS
113 
114 #include <math.h>
115 
116 /*
117  * Histogram bins count occurrences of values <= the bin label, as follows:
118  *
119  *   linear:  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10 or more
120  *     2**x:  0,   1,   2,   4,   8,  16,  32,  64, 128, 256, 512 or more
121  *    10**x:  0,   1,  10, 100, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9 or more
122  *
123  * We wish to count occurrences of 0 and 1 values separately, always.
124  */
125 static uint32_t
BinToVal(unsigned logscale,unsigned bin)126 BinToVal(unsigned logscale, unsigned bin)
127 {
128     MOZ_ASSERT(bin <= 10);
129     if (bin <= 1 || logscale == 0)
130         return bin;
131     --bin;
132     if (logscale == 2)
133         return JS_BIT(bin);
134     MOZ_ASSERT(logscale == 10);
135     return uint32_t(pow(10.0, (double) bin));
136 }
137 
138 static unsigned
ValToBin(unsigned logscale,uint32_t val)139 ValToBin(unsigned logscale, uint32_t val)
140 {
141     unsigned bin;
142 
143     if (val <= 1)
144         return val;
145     bin = (logscale == 10)
146         ? (unsigned) ceil(log10((double) val))
147         : (logscale == 2)
148         ? (unsigned) CeilingLog2Size(val)
149         : val;
150     return Min(bin, 10U);
151 }
152 
153 void
JS_BasicStatsAccum(JSBasicStats * bs,uint32_t val)154 JS_BasicStatsAccum(JSBasicStats* bs, uint32_t val)
155 {
156     unsigned oldscale, newscale, bin;
157     double mean;
158 
159     ++bs->num;
160     if (bs->max < val)
161         bs->max = val;
162     bs->sum += val;
163     bs->sqsum += (double)val * val;
164 
165     oldscale = bs->logscale;
166     if (oldscale != 10) {
167         mean = bs->sum / bs->num;
168         if (bs->max > 16 && mean > 8) {
169             newscale = (bs->max > 1e6 && mean > 1000) ? 10 : 2;
170             if (newscale != oldscale) {
171                 uint32_t newhist[11], newbin;
172 
173                 PodArrayZero(newhist);
174                 for (bin = 0; bin <= 10; bin++) {
175                     newbin = ValToBin(newscale, BinToVal(oldscale, bin));
176                     newhist[newbin] += bs->hist[bin];
177                 }
178                 js_memcpy(bs->hist, newhist, sizeof bs->hist);
179                 bs->logscale = newscale;
180             }
181         }
182     }
183 
184     bin = ValToBin(bs->logscale, val);
185     ++bs->hist[bin];
186 }
187 
188 double
JS_MeanAndStdDev(uint32_t num,double sum,double sqsum,double * sigma)189 JS_MeanAndStdDev(uint32_t num, double sum, double sqsum, double* sigma)
190 {
191     double var;
192 
193     if (num == 0 || sum == 0) {
194         *sigma = 0;
195         return 0;
196     }
197 
198     var = num * sqsum - sum * sum;
199     if (var < 0 || num == 1)
200         var = 0;
201     else
202         var /= (double)num * (num - 1);
203 
204     /* Windows says sqrt(0.0) is "-1.#J" (?!) so we must test. */
205     *sigma = (var != 0) ? sqrt(var) : 0;
206     return sum / num;
207 }
208 
209 void
JS_DumpBasicStats(JSBasicStats * bs,const char * title,FILE * fp)210 JS_DumpBasicStats(JSBasicStats* bs, const char* title, FILE* fp)
211 {
212     double mean, sigma;
213 
214     mean = JS_MeanAndStdDevBS(bs, &sigma);
215     fprintf(fp, "\nmean %s %g, std. deviation %g, max %lu\n",
216             title, mean, sigma, (unsigned long) bs->max);
217     JS_DumpHistogram(bs, fp);
218 }
219 
220 void
JS_DumpHistogram(JSBasicStats * bs,FILE * fp)221 JS_DumpHistogram(JSBasicStats* bs, FILE* fp)
222 {
223     unsigned bin;
224     uint32_t cnt, max;
225     double sum, mean;
226 
227     for (bin = 0, max = 0, sum = 0; bin <= 10; bin++) {
228         cnt = bs->hist[bin];
229         if (max < cnt)
230             max = cnt;
231         sum += cnt;
232     }
233     mean = sum / cnt;
234     for (bin = 0; bin <= 10; bin++) {
235         unsigned val = BinToVal(bs->logscale, bin);
236         unsigned end = (bin == 10) ? 0 : BinToVal(bs->logscale, bin + 1);
237         cnt = bs->hist[bin];
238         if (val + 1 == end)
239             fprintf(fp, "        [%6u]", val);
240         else if (end != 0)
241             fprintf(fp, "[%6u, %6u]", val, end - 1);
242         else
243             fprintf(fp, "[%6u,   +inf]", val);
244         fprintf(fp, ": %8u ", cnt);
245         if (cnt != 0) {
246             if (max > 1e6 && mean > 1e3)
247                 cnt = uint32_t(ceil(log10((double) cnt)));
248             else if (max > 16 && mean > 8)
249                 cnt = CeilingLog2Size(cnt);
250             for (unsigned i = 0; i < cnt; i++)
251                 putc('*', fp);
252         }
253         putc('\n', fp);
254     }
255 }
256 
257 #endif /* JS_BASIC_STATS */
258