/[jscoverage]/trunk/js/jsmath.cpp
ViewVC logotype

Contents of /trunk/js/jsmath.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 332 - (show annotations)
Thu Oct 23 19:03:33 2008 UTC (10 years, 11 months ago) by siliconforks
File size: 16545 byte(s)
Add SpiderMonkey from Firefox 3.1b1.

The following directories and files were removed:
correct/, correct.js
liveconnect/
nanojit/
t/
v8/
vprof/
xpconnect/
all JavaScript files (Y.js, call.js, if.js, math-partial-sums.js, md5.js, perfect.js, trace-test.js, trace.js)


1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 *
3 * ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 *
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
10 *
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
14 * License.
15 *
16 * The Original Code is Mozilla Communicator client code, released
17 * March 31, 1998.
18 *
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1998
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
25 *
26 * Alternatively, the contents of this file may be used under the terms of
27 * either of the GNU General Public License Version 2 or later (the "GPL"),
28 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
37 *
38 * ***** END LICENSE BLOCK ***** */
39
40 /*
41 * JS math package.
42 */
43 #include "jsstddef.h"
44 #include "jslibmath.h"
45 #include <stdlib.h>
46 #include "jstypes.h"
47 #include "jslong.h"
48 #include "prmjtime.h"
49 #include "jsapi.h"
50 #include "jsatom.h"
51 #include "jscntxt.h"
52 #include "jsversion.h"
53 #include "jslock.h"
54 #include "jsmath.h"
55 #include "jsnum.h"
56 #include "jsobj.h"
57
58 #ifndef M_E
59 #define M_E 2.7182818284590452354
60 #endif
61 #ifndef M_LOG2E
62 #define M_LOG2E 1.4426950408889634074
63 #endif
64 #ifndef M_LOG10E
65 #define M_LOG10E 0.43429448190325182765
66 #endif
67 #ifndef M_LN2
68 #define M_LN2 0.69314718055994530942
69 #endif
70 #ifndef M_LN10
71 #define M_LN10 2.30258509299404568402
72 #endif
73 #ifndef M_PI
74 #define M_PI 3.14159265358979323846
75 #endif
76 #ifndef M_SQRT2
77 #define M_SQRT2 1.41421356237309504880
78 #endif
79 #ifndef M_SQRT1_2
80 #define M_SQRT1_2 0.70710678118654752440
81 #endif
82
83 static JSConstDoubleSpec math_constants[] = {
84 {M_E, "E", 0, {0,0,0}},
85 {M_LOG2E, "LOG2E", 0, {0,0,0}},
86 {M_LOG10E, "LOG10E", 0, {0,0,0}},
87 {M_LN2, "LN2", 0, {0,0,0}},
88 {M_LN10, "LN10", 0, {0,0,0}},
89 {M_PI, "PI", 0, {0,0,0}},
90 {M_SQRT2, "SQRT2", 0, {0,0,0}},
91 {M_SQRT1_2, "SQRT1_2", 0, {0,0,0}},
92 {0,0,0,{0,0,0}}
93 };
94
95 JSClass js_MathClass = {
96 js_Math_str,
97 JSCLASS_HAS_CACHED_PROTO(JSProto_Math),
98 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
99 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
100 JSCLASS_NO_OPTIONAL_MEMBERS
101 };
102
103 static JSBool
104 math_abs(JSContext *cx, uintN argc, jsval *vp)
105 {
106 jsdouble x, z;
107
108 if (argc == 0) {
109 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
110 return JS_TRUE;
111 }
112 x = js_ValueToNumber(cx, &vp[2]);
113 if (JSVAL_IS_NULL(vp[2]))
114 return JS_FALSE;
115 z = fd_fabs(x);
116 return js_NewNumberInRootedValue(cx, z, vp);
117 }
118
119 static JSBool
120 math_acos(JSContext *cx, uintN argc, jsval *vp)
121 {
122 jsdouble x, z;
123
124 if (argc == 0) {
125 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
126 return JS_TRUE;
127 }
128 x = js_ValueToNumber(cx, &vp[2]);
129 if (JSVAL_IS_NULL(vp[2]))
130 return JS_FALSE;
131 #if !JS_USE_FDLIBM_MATH && defined(SOLARIS) && defined(__GNUC__)
132 if (x < -1 || 1 < x) {
133 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
134 return JS_TRUE;
135 }
136 #endif
137 z = fd_acos(x);
138 return js_NewNumberInRootedValue(cx, z, vp);
139 }
140
141 static JSBool
142 math_asin(JSContext *cx, uintN argc, jsval *vp)
143 {
144 jsdouble x, z;
145
146 if (argc == 0) {
147 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
148 return JS_TRUE;
149 }
150 x = js_ValueToNumber(cx, &vp[2]);
151 if (JSVAL_IS_NULL(vp[2]))
152 return JS_FALSE;
153 #if !JS_USE_FDLIBM_MATH && defined(SOLARIS) && defined(__GNUC__)
154 if (x < -1 || 1 < x) {
155 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
156 return JS_TRUE;
157 }
158 #endif
159 z = fd_asin(x);
160 return js_NewNumberInRootedValue(cx, z, vp);
161 }
162
163 static JSBool
164 math_atan(JSContext *cx, uintN argc, jsval *vp)
165 {
166 jsdouble x, z;
167
168 if (argc == 0) {
169 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
170 return JS_TRUE;
171 }
172 x = js_ValueToNumber(cx, &vp[2]);
173 if (JSVAL_IS_NULL(vp[2]))
174 return JS_FALSE;
175 z = fd_atan(x);
176 return js_NewNumberInRootedValue(cx, z, vp);
177 }
178
179 static JSBool
180 math_atan2(JSContext *cx, uintN argc, jsval *vp)
181 {
182 jsdouble x, y, z;
183
184 if (argc <= 1) {
185 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
186 return JS_TRUE;
187 }
188 x = js_ValueToNumber(cx, &vp[2]);
189 if (JSVAL_IS_NULL(vp[2]))
190 return JS_FALSE;
191 y = js_ValueToNumber(cx, &vp[3]);
192 if (JSVAL_IS_NULL(vp[3]))
193 return JS_FALSE;
194 #if defined(_MSC_VER)
195 /*
196 * MSVC's atan2 does not yield the result demanded by ECMA when both x
197 * and y are infinite.
198 * - The result is a multiple of pi/4.
199 * - The sign of x determines the sign of the result.
200 * - The sign of y determines the multiplicator, 1 or 3.
201 */
202 if (JSDOUBLE_IS_INFINITE(x) && JSDOUBLE_IS_INFINITE(y)) {
203 z = fd_copysign(M_PI / 4, x);
204 if (y < 0)
205 z *= 3;
206 return js_NewDoubleInRootedValue(cx, z, vp);
207 }
208 #endif
209
210 #if !JS_USE_FDLIBM_MATH && defined(SOLARIS) && defined(__GNUC__)
211 if (x == 0) {
212 if (JSDOUBLE_IS_NEGZERO(y)) {
213 z = fd_copysign(M_PI, x);
214 return js_NewDoubleInRootedValue(cx, z, vp);
215 }
216 if (y == 0) {
217 z = x;
218 return js_NewDoubleInRootedValue(cx, z, vp);
219 }
220 }
221 #endif
222 z = fd_atan2(x, y);
223 return js_NewNumberInRootedValue(cx, z, vp);
224 }
225
226 JSBool
227 js_math_ceil(JSContext *cx, uintN argc, jsval *vp)
228 {
229 jsdouble x, z;
230
231 if (argc == 0) {
232 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
233 return JS_TRUE;
234 }
235 x = js_ValueToNumber(cx, &vp[2]);
236 if (JSVAL_IS_NULL(vp[2]))
237 return JS_FALSE;
238 z = fd_ceil(x);
239 return js_NewNumberInRootedValue(cx, z, vp);
240 }
241
242 JSBool
243 js_math_cos(JSContext *cx, uintN argc, jsval *vp)
244 {
245 jsdouble x, z;
246
247 if (argc == 0) {
248 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
249 return JS_TRUE;
250 }
251 x = js_ValueToNumber(cx, &vp[2]);
252 if (JSVAL_IS_NULL(vp[2]))
253 return JS_FALSE;
254 z = fd_cos(x);
255 return js_NewNumberInRootedValue(cx, z, vp);
256 }
257
258 static JSBool
259 math_exp(JSContext *cx, uintN argc, jsval *vp)
260 {
261 jsdouble x, z;
262
263 if (argc == 0) {
264 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
265 return JS_TRUE;
266 }
267 x = js_ValueToNumber(cx, &vp[2]);
268 if (JSVAL_IS_NULL(vp[2]))
269 return JS_FALSE;
270 #ifdef _WIN32
271 if (!JSDOUBLE_IS_NaN(x)) {
272 if (x == *cx->runtime->jsPositiveInfinity) {
273 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
274 return JS_TRUE;
275 }
276 if (x == *cx->runtime->jsNegativeInfinity) {
277 *vp = JSVAL_ZERO;
278 return JS_TRUE;
279 }
280 }
281 #endif
282 z = fd_exp(x);
283 return js_NewNumberInRootedValue(cx, z, vp);
284 }
285
286 JSBool
287 js_math_floor(JSContext *cx, uintN argc, jsval *vp)
288 {
289 jsdouble x, z;
290
291 if (argc == 0) {
292 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
293 return JS_TRUE;
294 }
295 x = js_ValueToNumber(cx, &vp[2]);
296 if (JSVAL_IS_NULL(vp[2]))
297 return JS_FALSE;
298 z = fd_floor(x);
299 return js_NewNumberInRootedValue(cx, z, vp);
300 }
301
302 JSBool
303 js_math_log(JSContext *cx, uintN argc, jsval *vp)
304 {
305 jsdouble x, z;
306
307 if (argc == 0) {
308 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
309 return JS_TRUE;
310 }
311 x = js_ValueToNumber(cx, &vp[2]);
312 if (JSVAL_IS_NULL(vp[2]))
313 return JS_FALSE;
314 #if !JS_USE_FDLIBM_MATH && defined(SOLARIS) && defined(__GNUC__)
315 if (x < 0) {
316 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
317 return JS_TRUE;
318 }
319 #endif
320 z = fd_log(x);
321 return js_NewNumberInRootedValue(cx, z, vp);
322 }
323
324 JSBool
325 js_math_max(JSContext *cx, uintN argc, jsval *vp)
326 {
327 jsdouble x, z = *cx->runtime->jsNegativeInfinity;
328 jsval *argv;
329 uintN i;
330
331 if (argc == 0) {
332 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNegativeInfinity);
333 return JS_TRUE;
334 }
335 argv = vp + 2;
336 for (i = 0; i < argc; i++) {
337 x = js_ValueToNumber(cx, &argv[i]);
338 if (JSVAL_IS_NULL(argv[i]))
339 return JS_FALSE;
340 if (JSDOUBLE_IS_NaN(x)) {
341 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
342 return JS_TRUE;
343 }
344 if (x == 0 && x == z && fd_copysign(1.0, z) == -1)
345 z = x;
346 else
347 z = (x > z) ? x : z;
348 }
349 return js_NewNumberInRootedValue(cx, z, vp);
350 }
351
352 static JSBool
353 math_min(JSContext *cx, uintN argc, jsval *vp)
354 {
355 jsdouble x, z = *cx->runtime->jsPositiveInfinity;
356 jsval *argv;
357 uintN i;
358
359 if (argc == 0) {
360 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsPositiveInfinity);
361 return JS_TRUE;
362 }
363 argv = vp + 2;
364 for (i = 0; i < argc; i++) {
365 x = js_ValueToNumber(cx, &argv[i]);
366 if (JSVAL_IS_NULL(argv[i]))
367 return JS_FALSE;
368 if (JSDOUBLE_IS_NaN(x)) {
369 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
370 return JS_TRUE;
371 }
372 if (x == 0 && x == z && fd_copysign(1.0,x) == -1)
373 z = x;
374 else
375 z = (x < z) ? x : z;
376 }
377 return js_NewNumberInRootedValue(cx, z, vp);
378 }
379
380 JSBool
381 js_math_pow(JSContext *cx, uintN argc, jsval *vp)
382 {
383 jsdouble x, y, z;
384
385 if (argc <= 1) {
386 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
387 return JS_TRUE;
388 }
389 x = js_ValueToNumber(cx, &vp[2]);
390 if (JSVAL_IS_NULL(vp[2]))
391 return JS_FALSE;
392 y = js_ValueToNumber(cx, &vp[3]);
393 if (JSVAL_IS_NULL(vp[3]))
394 return JS_FALSE;
395 /*
396 * Because C99 and ECMA specify different behavior for pow(),
397 * we need to wrap the libm call to make it ECMA compliant.
398 */
399 if (!JSDOUBLE_IS_FINITE(y) && (x == 1.0 || x == -1.0)) {
400 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
401 return JS_TRUE;
402 }
403 /* pow(x, +-0) is always 1, even for x = NaN. */
404 if (y == 0) {
405 *vp = JSVAL_ONE;
406 return JS_TRUE;
407 }
408 z = fd_pow(x, y);
409 return js_NewNumberInRootedValue(cx, z, vp);
410 }
411
412 /*
413 * Math.random() support, lifted from java.util.Random.java.
414 */
415 static void
416 random_setSeed(JSRuntime *rt, int64 seed)
417 {
418 int64 tmp;
419
420 JSLL_I2L(tmp, 1000);
421 JSLL_DIV(seed, seed, tmp);
422 JSLL_XOR(tmp, seed, rt->rngMultiplier);
423 JSLL_AND(rt->rngSeed, tmp, rt->rngMask);
424 }
425
426 void
427 js_random_init(JSRuntime *rt)
428 {
429 int64 tmp, tmp2;
430
431 /* Do at most once. */
432 if (rt->rngInitialized)
433 return;
434 rt->rngInitialized = JS_TRUE;
435
436 /* rt->rngMultiplier = 0x5DEECE66DL */
437 JSLL_ISHL(tmp, 0x5, 32);
438 JSLL_UI2L(tmp2, 0xDEECE66DL);
439 JSLL_OR(rt->rngMultiplier, tmp, tmp2);
440
441 /* rt->rngAddend = 0xBL */
442 JSLL_I2L(rt->rngAddend, 0xBL);
443
444 /* rt->rngMask = (1L << 48) - 1 */
445 JSLL_I2L(tmp, 1);
446 JSLL_SHL(tmp2, tmp, 48);
447 JSLL_SUB(rt->rngMask, tmp2, tmp);
448
449 /* rt->rngDscale = (jsdouble)(1L << 53) */
450 JSLL_SHL(tmp2, tmp, 53);
451 JSLL_L2D(rt->rngDscale, tmp2);
452
453 /* Finally, set the seed from current time. */
454 random_setSeed(rt, PRMJ_Now());
455 }
456
457 static uint32
458 random_next(JSRuntime *rt, int bits)
459 {
460 int64 nextseed, tmp;
461 uint32 retval;
462
463 JSLL_MUL(nextseed, rt->rngSeed, rt->rngMultiplier);
464 JSLL_ADD(nextseed, nextseed, rt->rngAddend);
465 JSLL_AND(nextseed, nextseed, rt->rngMask);
466 rt->rngSeed = nextseed;
467 JSLL_USHR(tmp, nextseed, 48 - bits);
468 JSLL_L2I(retval, tmp);
469 return retval;
470 }
471
472 jsdouble
473 js_random_nextDouble(JSRuntime *rt)
474 {
475 int64 tmp, tmp2;
476 jsdouble d;
477
478 JSLL_ISHL(tmp, random_next(rt, 26), 27);
479 JSLL_UI2L(tmp2, random_next(rt, 27));
480 JSLL_ADD(tmp, tmp, tmp2);
481 JSLL_L2D(d, tmp);
482 return d / rt->rngDscale;
483 }
484
485 JSBool
486 js_math_random(JSContext *cx, uintN argc, jsval *vp)
487 {
488 JSRuntime *rt;
489 jsdouble z;
490
491 rt = cx->runtime;
492 JS_LOCK_RUNTIME(rt);
493 js_random_init(rt);
494 z = js_random_nextDouble(rt);
495 JS_UNLOCK_RUNTIME(rt);
496 return js_NewNumberInRootedValue(cx, z, vp);
497 }
498
499 #if defined _WIN32 && !defined WINCE && _MSC_VER < 1400
500 /* Try to work around apparent _copysign bustage in VC6 and VC7. */
501 double
502 js_copysign(double x, double y)
503 {
504 jsdpun xu, yu;
505
506 xu.d = x;
507 yu.d = y;
508 xu.s.hi &= ~JSDOUBLE_HI32_SIGNBIT;
509 xu.s.hi |= yu.s.hi & JSDOUBLE_HI32_SIGNBIT;
510 return xu.d;
511 }
512 #endif
513
514 static JSBool
515 math_round(JSContext *cx, uintN argc, jsval *vp)
516 {
517 jsdouble x, z;
518
519 if (argc == 0) {
520 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
521 return JS_TRUE;
522 }
523 x = js_ValueToNumber(cx, &vp[2]);
524 if (JSVAL_IS_NULL(vp[2]))
525 return JS_FALSE;
526 z = fd_copysign(fd_floor(x + 0.5), x);
527 return js_NewNumberInRootedValue(cx, z, vp);
528 }
529
530 JSBool
531 js_math_sin(JSContext *cx, uintN argc, jsval *vp)
532 {
533 jsdouble x, z;
534
535 if (argc == 0) {
536 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
537 return JS_TRUE;
538 }
539 x = js_ValueToNumber(cx, &vp[2]);
540 if (JSVAL_IS_NULL(vp[2]))
541 return JS_FALSE;
542 z = fd_sin(x);
543 return js_NewNumberInRootedValue(cx, z, vp);
544 }
545
546 JSBool
547 js_math_sqrt(JSContext *cx, uintN argc, jsval *vp)
548 {
549 jsdouble x, z;
550
551 if (argc == 0) {
552 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
553 return JS_TRUE;
554 }
555 x = js_ValueToNumber(cx, &vp[2]);
556 if (JSVAL_IS_NULL(vp[2]))
557 return JS_FALSE;
558 z = fd_sqrt(x);
559 return js_NewNumberInRootedValue(cx, z, vp);
560 }
561
562 static JSBool
563 math_tan(JSContext *cx, uintN argc, jsval *vp)
564 {
565 jsdouble x, z;
566
567 if (argc == 0) {
568 *vp = DOUBLE_TO_JSVAL(cx->runtime->jsNaN);
569 return JS_TRUE;
570 }
571 x = js_ValueToNumber(cx, &vp[2]);
572 if (JSVAL_IS_NULL(vp[2]))
573 return JS_FALSE;
574 z = fd_tan(x);
575 return js_NewNumberInRootedValue(cx, z, vp);
576 }
577
578 #if JS_HAS_TOSOURCE
579 static JSBool
580 math_toSource(JSContext *cx, uintN argc, jsval *vp)
581 {
582 *vp = ATOM_KEY(CLASS_ATOM(cx, Math));
583 return JS_TRUE;
584 }
585 #endif
586
587 static JSFunctionSpec math_static_methods[] = {
588 #if JS_HAS_TOSOURCE
589 JS_FN(js_toSource_str, math_toSource, 0, 0),
590 #endif
591 JS_FN("abs", math_abs, 1, 0),
592 JS_FN("acos", math_acos, 1, 0),
593 JS_FN("asin", math_asin, 1, 0),
594 JS_FN("atan", math_atan, 1, 0),
595 JS_FN("atan2", math_atan2, 2, 0),
596 JS_FN("ceil", js_math_ceil, 1, 0),
597 JS_FN("cos", js_math_cos, 1, 0),
598 JS_FN("exp", math_exp, 1, 0),
599 JS_FN("floor", js_math_floor, 1, 0),
600 JS_FN("log", js_math_log, 1, 0),
601 JS_FN("max", js_math_max, 2, 0),
602 JS_FN("min", math_min, 2, 0),
603 JS_FN("pow", js_math_pow, 2, 0),
604 JS_FN("random", js_math_random, 0, 0),
605 JS_FN("round", math_round, 1, 0),
606 JS_FN("sin", js_math_sin, 1, 0),
607 JS_FN("sqrt", js_math_sqrt, 1, 0),
608 JS_FN("tan", math_tan, 1, 0),
609 JS_FS_END
610 };
611
612 JSObject *
613 js_InitMathClass(JSContext *cx, JSObject *obj)
614 {
615 JSObject *Math;
616
617 Math = JS_NewObject(cx, &js_MathClass, NULL, obj);
618 if (!Math)
619 return NULL;
620 if (!JS_DefineProperty(cx, obj, js_Math_str, OBJECT_TO_JSVAL(Math),
621 JS_PropertyStub, JS_PropertyStub,
622 JSPROP_READONLY | JSPROP_PERMANENT))
623 return NULL;
624
625 if (!JS_DefineFunctions(cx, Math, math_static_methods))
626 return NULL;
627 if (!JS_DefineConstDoubles(cx, Math, math_constants))
628 return NULL;
629 return Math;
630 }

  ViewVC Help
Powered by ViewVC 1.1.24