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 jsmath_h
8 #define jsmath_h
9 
10 #include "mozilla/MemoryReporting.h"
11 
12 #include <cmath>
13 
14 #include "NamespaceImports.h"
15 
16 namespace js {
17 
18 typedef double (*UnaryFunType)(double);
19 
20 class MathCache
21 {
22   public:
23     enum MathFuncId {
24         Zero,
25         Sin, Cos, Tan, Sinh, Cosh, Tanh, Asin, Acos, Atan, Asinh, Acosh, Atanh,
26         Sqrt, Log, Log10, Log2, Log1p, Exp, Expm1, Cbrt, Trunc, Sign
27     };
28 
29   private:
30     static const unsigned SizeLog2 = 12;
31     static const unsigned Size = 1 << SizeLog2;
32     struct Entry { double in; MathFuncId id; double out; };
33     Entry table[Size];
34 
35   public:
36     MathCache();
37 
hash(double x,MathFuncId id)38     unsigned hash(double x, MathFuncId id) {
39         union { double d; struct { uint32_t one, two; } s; } u = { x };
40         uint32_t hash32 = u.s.one ^ u.s.two;
41         hash32 += uint32_t(id) << 8;
42         uint16_t hash16 = uint16_t(hash32 ^ (hash32 >> 16));
43         return (hash16 & (Size - 1)) ^ (hash16 >> (16 - SizeLog2));
44     }
45 
46     /*
47      * N.B. lookup uses double-equality. This is only safe if hash() maps +0
48      * and -0 to different table entries, which is asserted in MathCache().
49      */
lookup(UnaryFunType f,double x,MathFuncId id)50     double lookup(UnaryFunType f, double x, MathFuncId id) {
51         unsigned index = hash(x, id);
52         Entry& e = table[index];
53         if (e.in == x && e.id == id)
54             return e.out;
55         e.in = x;
56         e.id = id;
57         return e.out = f(x);
58     }
59 
isCached(double x,MathFuncId id,double * r,unsigned * index)60     bool isCached(double x, MathFuncId id, double *r, unsigned *index) {
61         *index = hash(x, id);
62         Entry& e = table[*index];
63         if (e.in == x && e.id == id) {
64             *r = e.out;
65             return true;
66         }
67         return false;
68     }
69 
store(MathFuncId id,double x,double v,unsigned index)70     void store(MathFuncId id, double x, double v, unsigned index) {
71         Entry &e = table[index];
72         if (e.in == x && e.id == id)
73             return;
74         e.in = x;
75         e.id = id;
76         e.out = v;
77     }
78 
79     size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
80 };
81 
82 /*
83  * JS math functions.
84  */
85 
86 extern JSObject*
87 InitMathClass(JSContext* cx, HandleObject obj);
88 
89 extern uint64_t
90 GenerateRandomSeed();
91 
92 // Fill |seed[0]| and |seed[1]| with random bits, suitable for
93 // seeding a XorShift128+ random number generator.
94 extern void
95 GenerateXorShift128PlusSeed(mozilla::Array<uint64_t, 2>& seed);
96 
97 extern uint64_t
98 random_next(uint64_t* rngState, int bits);
99 
100 extern bool
101 math_random(JSContext* cx, unsigned argc, js::Value* vp);
102 
103 extern bool
104 math_abs_handle(JSContext* cx, js::HandleValue v, js::MutableHandleValue r);
105 
106 extern bool
107 math_abs(JSContext* cx, unsigned argc, js::Value* vp);
108 
109 extern double
110 math_max_impl(double x, double y);
111 
112 extern bool
113 math_max(JSContext* cx, unsigned argc, js::Value* vp);
114 
115 extern double
116 math_min_impl(double x, double y);
117 
118 extern bool
119 math_min(JSContext* cx, unsigned argc, js::Value* vp);
120 
121 extern bool
122 math_sqrt(JSContext* cx, unsigned argc, js::Value* vp);
123 
124 extern bool
125 math_pow_handle(JSContext* cx, js::HandleValue base, js::HandleValue power,
126                 js::MutableHandleValue result);
127 
128 extern bool
129 math_pow(JSContext* cx, unsigned argc, js::Value* vp);
130 
131 extern bool
132 minmax_impl(JSContext* cx, bool max, js::HandleValue a, js::HandleValue b,
133             js::MutableHandleValue res);
134 
135 extern void
136 math_sincos_uncached(double x, double *sin, double *cos);
137 
138 extern void
139 math_sincos_impl(MathCache* mathCache, double x, double *sin, double *cos);
140 
141 extern bool
142 math_sqrt_handle(JSContext* cx, js::HandleValue number, js::MutableHandleValue result);
143 
144 extern bool
145 math_imul_handle(JSContext* cx, HandleValue lhs, HandleValue rhs, MutableHandleValue res);
146 
147 extern bool
148 math_imul(JSContext* cx, unsigned argc, js::Value* vp);
149 
150 extern bool
151 RoundFloat32(JSContext* cx, HandleValue v, float* out);
152 
153 extern bool
154 RoundFloat32(JSContext* cx, HandleValue arg, MutableHandleValue res);
155 
156 extern bool
157 math_fround(JSContext* cx, unsigned argc, js::Value* vp);
158 
159 extern bool
160 math_log(JSContext* cx, unsigned argc, js::Value* vp);
161 
162 extern double
163 math_log_impl(MathCache* cache, double x);
164 
165 extern double
166 math_log_uncached(double x);
167 
168 extern bool
169 math_log_handle(JSContext* cx, HandleValue val, MutableHandleValue res);
170 
171 extern bool
172 math_sin(JSContext* cx, unsigned argc, js::Value* vp);
173 
174 extern double
175 math_sin_impl(MathCache* cache, double x);
176 
177 extern double
178 math_sin_uncached(double x);
179 
180 extern bool
181 math_sin_handle(JSContext* cx, HandleValue val, MutableHandleValue res);
182 
183 extern bool
184 math_cos(JSContext* cx, unsigned argc, js::Value* vp);
185 
186 extern double
187 math_cos_impl(MathCache* cache, double x);
188 
189 extern double
190 math_cos_uncached(double x);
191 
192 extern bool
193 math_exp(JSContext* cx, unsigned argc, js::Value* vp);
194 
195 extern double
196 math_exp_impl(MathCache* cache, double x);
197 
198 extern double
199 math_exp_uncached(double x);
200 
201 extern bool
202 math_tan(JSContext* cx, unsigned argc, js::Value* vp);
203 
204 extern double
205 math_tan_impl(MathCache* cache, double x);
206 
207 extern double
208 math_tan_uncached(double x);
209 
210 extern bool
211 math_log10(JSContext* cx, unsigned argc, js::Value* vp);
212 
213 extern bool
214 math_log2(JSContext* cx, unsigned argc, js::Value* vp);
215 
216 extern bool
217 math_log1p(JSContext* cx, unsigned argc, js::Value* vp);
218 
219 extern bool
220 math_expm1(JSContext* cx, unsigned argc, js::Value* vp);
221 
222 extern bool
223 math_cosh(JSContext* cx, unsigned argc, js::Value* vp);
224 
225 extern bool
226 math_sinh(JSContext* cx, unsigned argc, js::Value* vp);
227 
228 extern bool
229 math_tanh(JSContext* cx, unsigned argc, js::Value* vp);
230 
231 extern bool
232 math_acosh(JSContext* cx, unsigned argc, js::Value* vp);
233 
234 extern bool
235 math_asinh(JSContext* cx, unsigned argc, js::Value* vp);
236 
237 extern bool
238 math_atanh(JSContext* cx, unsigned argc, js::Value* vp);
239 
240 extern double
241 ecmaHypot(double x, double y);
242 
243 extern double
244 hypot3(double x, double y, double z);
245 
246 extern double
247 hypot4(double x, double y, double z, double w);
248 
249 extern bool
250 math_hypot(JSContext* cx, unsigned argc, Value* vp);
251 
252 extern bool
253 math_hypot_handle(JSContext* cx, HandleValueArray args, MutableHandleValue res);
254 
255 extern bool
256 math_trunc(JSContext* cx, unsigned argc, Value* vp);
257 
258 extern bool
259 math_sign(JSContext* cx, unsigned argc, Value* vp);
260 
261 extern bool
262 math_cbrt(JSContext* cx, unsigned argc, Value* vp);
263 
264 extern bool
265 math_asin(JSContext* cx, unsigned argc, Value* vp);
266 
267 extern bool
268 math_acos(JSContext* cx, unsigned argc, Value* vp);
269 
270 extern bool
271 math_atan(JSContext* cx, unsigned argc, Value* vp);
272 
273 extern bool
274 math_atan2_handle(JSContext* cx, HandleValue y, HandleValue x, MutableHandleValue res);
275 
276 extern bool
277 math_atan2(JSContext* cx, unsigned argc, Value* vp);
278 
279 extern double
280 ecmaAtan2(double x, double y);
281 
282 extern double
283 math_atan_impl(MathCache* cache, double x);
284 
285 extern double
286 math_atan_uncached(double x);
287 
288 extern bool
289 math_atan(JSContext* cx, unsigned argc, js::Value* vp);
290 
291 extern double
292 math_asin_impl(MathCache* cache, double x);
293 
294 extern double
295 math_asin_uncached(double x);
296 
297 extern bool
298 math_asin(JSContext* cx, unsigned argc, js::Value* vp);
299 
300 extern double
301 math_acos_impl(MathCache* cache, double x);
302 
303 extern double
304 math_acos_uncached(double x);
305 
306 extern bool
307 math_acos(JSContext* cx, unsigned argc, js::Value* vp);
308 
309 extern bool
310 math_ceil_handle(JSContext* cx, HandleValue value, MutableHandleValue res);
311 
312 extern bool
313 math_ceil(JSContext* cx, unsigned argc, Value* vp);
314 
315 extern double
316 math_ceil_impl(double x);
317 
318 extern bool
319 math_clz32(JSContext* cx, unsigned argc, Value* vp);
320 
321 extern bool
322 math_floor_handle(JSContext* cx, HandleValue v, MutableHandleValue r);
323 
324 extern bool
325 math_floor(JSContext* cx, unsigned argc, Value* vp);
326 
327 extern double
328 math_floor_impl(double x);
329 
330 template<typename T>
331 extern T GetBiggestNumberLessThan(T x);
332 
333 extern bool
334 math_round_handle(JSContext* cx, HandleValue arg, MutableHandleValue res);
335 
336 extern bool
337 math_round(JSContext* cx, unsigned argc, Value* vp);
338 
339 extern double
340 math_round_impl(double x);
341 
342 extern float
343 math_roundf_impl(float x);
344 
345 extern double
346 powi(double x, int y);
347 
348 extern double
349 ecmaPow(double x, double y);
350 
351 extern bool
352 math_imul(JSContext* cx, unsigned argc, Value* vp);
353 
354 extern double
355 math_log10_impl(MathCache* cache, double x);
356 
357 extern double
358 math_log10_uncached(double x);
359 
360 extern double
361 math_log2_impl(MathCache* cache, double x);
362 
363 extern double
364 math_log2_uncached(double x);
365 
366 extern double
367 math_log1p_impl(MathCache* cache, double x);
368 
369 extern double
370 math_log1p_uncached(double x);
371 
372 extern double
373 math_expm1_impl(MathCache* cache, double x);
374 
375 extern double
376 math_expm1_uncached(double x);
377 
378 extern double
379 math_cosh_impl(MathCache* cache, double x);
380 
381 extern double
382 math_cosh_uncached(double x);
383 
384 extern double
385 math_sinh_impl(MathCache* cache, double x);
386 
387 extern double
388 math_sinh_uncached(double x);
389 
390 extern double
391 math_tanh_impl(MathCache* cache, double x);
392 
393 extern double
394 math_tanh_uncached(double x);
395 
396 extern double
397 math_acosh_impl(MathCache* cache, double x);
398 
399 extern double
400 math_acosh_uncached(double x);
401 
402 extern double
403 math_asinh_impl(MathCache* cache, double x);
404 
405 extern double
406 math_asinh_uncached(double x);
407 
408 extern double
409 math_atanh_impl(MathCache* cache, double x);
410 
411 extern double
412 math_atanh_uncached(double x);
413 
414 extern double
415 math_trunc_impl(MathCache* cache, double x);
416 
417 extern double
418 math_trunc_uncached(double x);
419 
420 extern double
421 math_sign_impl(MathCache* cache, double x);
422 
423 extern double
424 math_sign_uncached(double x);
425 
426 extern double
427 math_cbrt_impl(MathCache* cache, double x);
428 
429 extern double
430 math_cbrt_uncached(double x);
431 
432 } /* namespace js */
433 
434 #endif /* jsmath_h */
435